diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2025-08-27 10:59:16 +0300 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2025-08-27 10:59:28 +0300 |
| commit | c637d4ce9978d2ceb9aa678c37dd69374d479bd6 (patch) | |
| tree | e56705f2e12accae51e45a906bbe6222acf29651 | |
| parent | a03a7bd1a321ccb6eab91d1279abdb55ee1814f9 (diff) | |
| download | niri-c637d4ce9978d2ceb9aa678c37dd69374d479bd6.tar.gz niri-c637d4ce9978d2ceb9aa678c37dd69374d479bd6.tar.bz2 niri-c637d4ce9978d2ceb9aa678c37dd69374d479bd6.zip | |
config: Move some stuff to utils
| -rw-r--r-- | niri-config/src/animations.rs | 3 | ||||
| -rw-r--r-- | niri-config/src/binds.rs | 2 | ||||
| -rw-r--r-- | niri-config/src/input.rs | 3 | ||||
| -rw-r--r-- | niri-config/src/layout.rs | 3 | ||||
| -rw-r--r-- | niri-config/src/lib.rs | 162 | ||||
| -rw-r--r-- | niri-config/src/utils.rs | 160 |
6 files changed, 169 insertions, 164 deletions
diff --git a/niri-config/src/animations.rs b/niri-config/src/animations.rs index a119ba19..9a870834 100644 --- a/niri-config/src/animations.rs +++ b/niri-config/src/animations.rs @@ -1,7 +1,8 @@ use knuffel::errors::DecodeError; use knuffel::Decode as _; -use crate::{expect_only_children, parse_arg_node, FloatOrInt}; +use crate::utils::{expect_only_children, parse_arg_node}; +use crate::FloatOrInt; #[derive(knuffel::Decode, Debug, Clone, PartialEq)] pub struct Animations { diff --git a/niri-config/src/binds.rs b/niri-config/src/binds.rs index 2cdc96cd..f476ac2d 100644 --- a/niri-config/src/binds.rs +++ b/niri-config/src/binds.rs @@ -12,7 +12,7 @@ use smithay::input::keyboard::keysyms::KEY_NoSymbol; use smithay::input::keyboard::xkb::{keysym_from_name, KEYSYM_CASE_INSENSITIVE}; use smithay::input::keyboard::Keysym; -use crate::expect_only_children; +use crate::utils::expect_only_children; #[derive(Debug, Default, PartialEq)] pub struct Binds(pub Vec<Bind>); diff --git a/niri-config/src/input.rs b/niri-config/src/input.rs index c5d4a038..61f1a4b8 100644 --- a/niri-config/src/input.rs +++ b/niri-config/src/input.rs @@ -5,7 +5,8 @@ use smithay::input::keyboard::XkbConfig; use smithay::reexports::input; use crate::binds::Modifiers; -use crate::{FloatOrInt, Percent}; +use crate::utils::Percent; +use crate::FloatOrInt; #[derive(knuffel::Decode, Debug, Default, PartialEq)] pub struct Input { diff --git a/niri-config/src/layout.rs b/niri-config/src/layout.rs index 6f9c9135..768199d5 100644 --- a/niri-config/src/layout.rs +++ b/niri-config/src/layout.rs @@ -4,7 +4,8 @@ use niri_ipc::{ColumnDisplay, SizeChange}; use crate::appearance::{ Border, FocusRing, InsertHint, Shadow, TabIndicator, DEFAULT_BACKGROUND_COLOR, }; -use crate::{expect_only_children, Color, FloatOrInt}; +use crate::utils::expect_only_children; +use crate::{Color, FloatOrInt}; #[derive(knuffel::Decode, Debug, Clone, PartialEq)] pub struct Layout { diff --git a/niri-config/src/lib.rs b/niri-config/src/lib.rs index 1f44b041..dfc9ab2d 100644 --- a/niri-config/src/lib.rs +++ b/niri-config/src/lib.rs @@ -5,10 +5,9 @@ use std::ffi::OsStr; use std::fs::{self, File}; use std::io::Write; use std::path::{Path, PathBuf}; -use std::str::FromStr; use knuffel::errors::DecodeError; -use miette::{miette, Context, IntoDiagnostic}; +use miette::{Context, IntoDiagnostic}; pub mod animations; pub mod appearance; @@ -33,6 +32,7 @@ pub use crate::input::{Input, ModKey, ScrollMethod, TrackLayout, WarpMouseToFocu pub use crate::layer_rule::LayerRule; pub use crate::layout::*; pub use crate::output::{Output, OutputName, Outputs, Position, Vrr}; +pub use crate::utils::FloatOrInt; pub use crate::window_rule::{FloatingPosition, RelativeTo, WindowRule}; #[derive(knuffel::Decode, Debug, PartialEq)] @@ -89,13 +89,6 @@ pub struct Config { pub workspaces: Vec<Workspace>, } -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct Percent(pub f64); - -// MIN and MAX generics are only used during parsing to check the value. -#[derive(Debug, Default, Clone, Copy, PartialEq)] -pub struct FloatOrInt<const MIN: i32, const MAX: i32>(pub f64); - #[derive(knuffel::Decode, Debug, Clone, PartialEq, Eq)] pub struct SpawnAtStartup { #[knuffel(arguments)] @@ -210,72 +203,6 @@ pub struct Workspace { #[derive(Debug, Clone, PartialEq, Eq)] pub struct WorkspaceName(pub String); -impl<S: knuffel::traits::ErrorSpan, const MIN: i32, const MAX: i32> knuffel::DecodeScalar<S> - for FloatOrInt<MIN, MAX> -{ - fn type_check( - type_name: &Option<knuffel::span::Spanned<knuffel::ast::TypeName, S>>, - ctx: &mut knuffel::decode::Context<S>, - ) { - if let Some(type_name) = &type_name { - ctx.emit_error(DecodeError::unexpected( - type_name, - "type name", - "no type name expected for this node", - )); - } - } - - fn raw_decode( - val: &knuffel::span::Spanned<knuffel::ast::Literal, S>, - ctx: &mut knuffel::decode::Context<S>, - ) -> Result<Self, DecodeError<S>> { - match &**val { - knuffel::ast::Literal::Int(ref value) => match value.try_into() { - Ok(v) => { - if (MIN..=MAX).contains(&v) { - Ok(FloatOrInt(f64::from(v))) - } else { - ctx.emit_error(DecodeError::conversion( - val, - format!("value must be between {MIN} and {MAX}"), - )); - Ok(FloatOrInt::default()) - } - } - Err(e) => { - ctx.emit_error(DecodeError::conversion(val, e)); - Ok(FloatOrInt::default()) - } - }, - knuffel::ast::Literal::Decimal(ref value) => match value.try_into() { - Ok(v) => { - if (f64::from(MIN)..=f64::from(MAX)).contains(&v) { - Ok(FloatOrInt(v)) - } else { - ctx.emit_error(DecodeError::conversion( - val, - format!("value must be between {MIN} and {MAX}"), - )); - Ok(FloatOrInt::default()) - } - } - Err(e) => { - ctx.emit_error(DecodeError::conversion(val, e)); - Ok(FloatOrInt::default()) - } - }, - _ => { - ctx.emit_error(DecodeError::unsupported( - val, - "Unsupported value, only numbers are recognized", - )); - Ok(FloatOrInt::default()) - } - } - } -} - #[derive(Debug, Clone)] pub enum ConfigPath { /// Explicitly set config path. @@ -418,74 +345,6 @@ impl Default for Config { } } -fn expect_only_children<S>( - node: &knuffel::ast::SpannedNode<S>, - ctx: &mut knuffel::decode::Context<S>, -) where - S: knuffel::traits::ErrorSpan, -{ - if let Some(type_name) = &node.type_name { - ctx.emit_error(DecodeError::unexpected( - type_name, - "type name", - "no type name expected for this node", - )); - } - - for val in node.arguments.iter() { - ctx.emit_error(DecodeError::unexpected( - &val.literal, - "argument", - "no arguments expected for this node", - )) - } - - for name in node.properties.keys() { - ctx.emit_error(DecodeError::unexpected( - name, - "property", - "no properties expected for this node", - )) - } -} - -fn parse_arg_node<S: knuffel::traits::ErrorSpan, T: knuffel::traits::DecodeScalar<S>>( - name: &str, - node: &knuffel::ast::SpannedNode<S>, - ctx: &mut knuffel::decode::Context<S>, -) -> Result<T, DecodeError<S>> { - let mut iter_args = node.arguments.iter(); - let val = iter_args.next().ok_or_else(|| { - DecodeError::missing(node, format!("additional argument `{name}` is required")) - })?; - - let value = knuffel::traits::DecodeScalar::decode(val, ctx)?; - - if let Some(val) = iter_args.next() { - ctx.emit_error(DecodeError::unexpected( - &val.literal, - "argument", - "unexpected argument", - )); - } - for name in node.properties.keys() { - ctx.emit_error(DecodeError::unexpected( - name, - "property", - format!("unexpected property `{}`", name.escape_default()), - )); - } - for child in node.children() { - ctx.emit_error(DecodeError::unexpected( - child, - "node", - format!("unexpected node `{}`", child.node_name.escape_default()), - )); - } - - Ok(value) -} - impl<S: knuffel::traits::ErrorSpan> knuffel::DecodeScalar<S> for WorkspaceName { fn type_check( type_name: &Option<knuffel::span::Spanned<knuffel::ast::TypeName, S>>, @@ -537,23 +396,6 @@ impl<S: knuffel::traits::ErrorSpan> knuffel::DecodeScalar<S> for WorkspaceName { } } -impl FromStr for Percent { - type Err = miette::Error; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - let Some((value, empty)) = s.split_once('%') else { - return Err(miette!("value must end with '%'")); - }; - - if !empty.is_empty() { - return Err(miette!("trailing characters after '%' are not allowed")); - } - - let value: f64 = value.parse().map_err(|_| miette!("error parsing value"))?; - Ok(Percent(value / 100.)) - } -} - #[cfg(test)] mod tests { use insta::assert_debug_snapshot; diff --git a/niri-config/src/utils.rs b/niri-config/src/utils.rs index cce4f398..77baac5e 100644 --- a/niri-config/src/utils.rs +++ b/niri-config/src/utils.rs @@ -1,7 +1,16 @@ use std::str::FromStr; +use knuffel::errors::DecodeError; +use miette::miette; use regex::Regex; +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Percent(pub f64); + +// MIN and MAX generics are only used during parsing to check the value. +#[derive(Debug, Default, Clone, Copy, PartialEq)] +pub struct FloatOrInt<const MIN: i32, const MAX: i32>(pub f64); + /// `Regex` that implements `PartialEq` by its string form. #[derive(Debug, Clone)] pub struct RegexEq(pub Regex); @@ -21,3 +30,154 @@ impl FromStr for RegexEq { Regex::from_str(s).map(Self) } } + +impl FromStr for Percent { + type Err = miette::Error; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + let Some((value, empty)) = s.split_once('%') else { + return Err(miette!("value must end with '%'")); + }; + + if !empty.is_empty() { + return Err(miette!("trailing characters after '%' are not allowed")); + } + + let value: f64 = value.parse().map_err(|_| miette!("error parsing value"))?; + Ok(Percent(value / 100.)) + } +} + +impl<S: knuffel::traits::ErrorSpan, const MIN: i32, const MAX: i32> knuffel::DecodeScalar<S> + for FloatOrInt<MIN, MAX> +{ + fn type_check( + type_name: &Option<knuffel::span::Spanned<knuffel::ast::TypeName, S>>, + ctx: &mut knuffel::decode::Context<S>, + ) { + if let Some(type_name) = &type_name { + ctx.emit_error(DecodeError::unexpected( + type_name, + "type name", + "no type name expected for this node", + )); + } + } + + fn raw_decode( + val: &knuffel::span::Spanned<knuffel::ast::Literal, S>, + ctx: &mut knuffel::decode::Context<S>, + ) -> Result<Self, DecodeError<S>> { + match &**val { + knuffel::ast::Literal::Int(ref value) => match value.try_into() { + Ok(v) => { + if (MIN..=MAX).contains(&v) { + Ok(FloatOrInt(f64::from(v))) + } else { + ctx.emit_error(DecodeError::conversion( + val, + format!("value must be between {MIN} and {MAX}"), + )); + Ok(FloatOrInt::default()) + } + } + Err(e) => { + ctx.emit_error(DecodeError::conversion(val, e)); + Ok(FloatOrInt::default()) + } + }, + knuffel::ast::Literal::Decimal(ref value) => match value.try_into() { + Ok(v) => { + if (f64::from(MIN)..=f64::from(MAX)).contains(&v) { + Ok(FloatOrInt(v)) + } else { + ctx.emit_error(DecodeError::conversion( + val, + format!("value must be between {MIN} and {MAX}"), + )); + Ok(FloatOrInt::default()) + } + } + Err(e) => { + ctx.emit_error(DecodeError::conversion(val, e)); + Ok(FloatOrInt::default()) + } + }, + _ => { + ctx.emit_error(DecodeError::unsupported( + val, + "Unsupported value, only numbers are recognized", + )); + Ok(FloatOrInt::default()) + } + } + } +} + +pub fn expect_only_children<S>( + node: &knuffel::ast::SpannedNode<S>, + ctx: &mut knuffel::decode::Context<S>, +) where + S: knuffel::traits::ErrorSpan, +{ + if let Some(type_name) = &node.type_name { + ctx.emit_error(DecodeError::unexpected( + type_name, + "type name", + "no type name expected for this node", + )); + } + + for val in node.arguments.iter() { + ctx.emit_error(DecodeError::unexpected( + &val.literal, + "argument", + "no arguments expected for this node", + )) + } + + for name in node.properties.keys() { + ctx.emit_error(DecodeError::unexpected( + name, + "property", + "no properties expected for this node", + )) + } +} + +pub fn parse_arg_node<S: knuffel::traits::ErrorSpan, T: knuffel::traits::DecodeScalar<S>>( + name: &str, + node: &knuffel::ast::SpannedNode<S>, + ctx: &mut knuffel::decode::Context<S>, +) -> Result<T, DecodeError<S>> { + let mut iter_args = node.arguments.iter(); + let val = iter_args.next().ok_or_else(|| { + DecodeError::missing(node, format!("additional argument `{name}` is required")) + })?; + + let value = knuffel::traits::DecodeScalar::decode(val, ctx)?; + + if let Some(val) = iter_args.next() { + ctx.emit_error(DecodeError::unexpected( + &val.literal, + "argument", + "unexpected argument", + )); + } + for name in node.properties.keys() { + ctx.emit_error(DecodeError::unexpected( + name, + "property", + format!("unexpected property `{}`", name.escape_default()), + )); + } + for child in node.children() { + ctx.emit_error(DecodeError::unexpected( + child, + "node", + format!("unexpected node `{}`", child.node_name.escape_default()), + )); + } + + Ok(value) +} |
