aboutsummaryrefslogtreecommitdiff
path: root/niri-config/src/workspace.rs
diff options
context:
space:
mode:
Diffstat (limited to 'niri-config/src/workspace.rs')
-rw-r--r--niri-config/src/workspace.rs63
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()))
+ }
+ }
+ }
+}