diff options
Diffstat (limited to 'niri-config/src/workspace.rs')
| -rw-r--r-- | niri-config/src/workspace.rs | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/niri-config/src/workspace.rs b/niri-config/src/workspace.rs new file mode 100644 index 00000000..e502bdb7 --- /dev/null +++ b/niri-config/src/workspace.rs @@ -0,0 +1,63 @@ +use knuffel::errors::DecodeError; + +#[derive(knuffel::Decode, Debug, Clone, PartialEq, Eq)] +pub struct Workspace { + #[knuffel(argument)] + pub name: WorkspaceName, + #[knuffel(child, unwrap(argument))] + pub open_on_output: Option<String>, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct WorkspaceName(pub String); + +impl<S: knuffel::traits::ErrorSpan> knuffel::DecodeScalar<S> for WorkspaceName { + 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<WorkspaceName, DecodeError<S>> { + #[derive(Debug)] + struct WorkspaceNameSet(Vec<String>); + match &**val { + knuffel::ast::Literal::String(ref s) => { + let mut name_set: Vec<String> = match ctx.get::<WorkspaceNameSet>() { + Some(h) => h.0.clone(), + None => Vec::new(), + }; + + if name_set.iter().any(|name| name.eq_ignore_ascii_case(s)) { + ctx.emit_error(DecodeError::unexpected( + val, + "named workspace", + format!("duplicate named workspace: {s}"), + )); + return Ok(Self(String::new())); + } + + name_set.push(s.to_string()); + ctx.set(WorkspaceNameSet(name_set)); + Ok(Self(s.clone().into())) + } + _ => { + ctx.emit_error(DecodeError::unsupported( + val, + "workspace names must be strings", + )); + Ok(Self(String::new())) + } + } + } +} |
