eww/crates/yuck/src/config/script_var_definition.rs
2023-02-25 17:08:57 +01:00

111 lines
3.9 KiB
Rust

use simplexpr::{dynval::DynVal, SimplExpr};
use crate::{
error::{DiagError, DiagResult, DiagResultExt},
format_diagnostic::ToDiagnostic,
parser::{ast::Ast, ast_iterator::AstIterator, from_ast::FromAstElementContent},
};
use eww_shared_util::{Span, VarName};
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
pub enum ScriptVarDefinition {
Poll(PollScriptVar),
Listen(ListenScriptVar),
}
impl ScriptVarDefinition {
pub fn name_span(&self) -> Span {
match self {
ScriptVarDefinition::Poll(x) => x.name_span,
ScriptVarDefinition::Listen(x) => x.name_span,
}
}
pub fn name(&self) -> &VarName {
match self {
ScriptVarDefinition::Poll(x) => &x.name,
ScriptVarDefinition::Listen(x) => &x.name,
}
}
pub fn command_span(&self) -> Option<Span> {
match self {
ScriptVarDefinition::Poll(x) => match x.command {
VarSource::Shell(span, ..) => Some(span),
VarSource::Function(_) => None,
},
ScriptVarDefinition::Listen(x) => Some(x.command_span),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
pub enum VarSource {
// TODO allow for other executors? (python, etc)
Shell(Span, String),
#[serde(skip)]
Function(fn() -> Result<DynVal, Box<dyn std::error::Error + Sync + Send + 'static>>),
}
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
pub struct PollScriptVar {
pub name: VarName,
pub run_while_expr: SimplExpr,
pub command: VarSource,
pub initial_value: Option<DynVal>,
pub interval: std::time::Duration,
pub name_span: Span,
}
impl FromAstElementContent for PollScriptVar {
const ELEMENT_NAME: &'static str = "defpoll";
fn from_tail<I: Iterator<Item = Ast>>(_span: Span, mut iter: AstIterator<I>) -> DiagResult<Self> {
let result: DiagResult<_> = try {
let (name_span, name) = iter.expect_symbol()?;
let mut attrs = iter.expect_key_values()?;
let initial_value = Some(attrs.primitive_optional("initial")?.unwrap_or_else(|| DynVal::from_string(String::new())));
let interval =
attrs.primitive_required::<DynVal, _>("interval")?.as_duration().map_err(|e| DiagError(e.to_diagnostic()))?;
let (script_span, script) = iter.expect_literal()?;
let run_while_expr =
attrs.ast_optional::<SimplExpr>("run-while")?.unwrap_or_else(|| SimplExpr::Literal(DynVal::from(true)));
iter.expect_done()?;
Self {
name_span,
name: VarName(name),
run_while_expr,
command: VarSource::Shell(script_span, script.to_string()),
initial_value,
interval,
}
};
result.note(r#"Expected format: `(defpoll name :interval "10s" "echo 'a shell script'")`"#)
}
}
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
pub struct ListenScriptVar {
pub name: VarName,
pub command: String,
pub initial_value: DynVal,
pub command_span: Span,
pub name_span: Span,
}
impl FromAstElementContent for ListenScriptVar {
const ELEMENT_NAME: &'static str = "deflisten";
fn from_tail<I: Iterator<Item = Ast>>(_span: Span, mut iter: AstIterator<I>) -> DiagResult<Self> {
let result: DiagResult<_> = try {
let (name_span, name) = iter.expect_symbol()?;
let mut attrs = iter.expect_key_values()?;
let initial_value = attrs.primitive_optional("initial")?.unwrap_or_else(|| DynVal::from_string(String::new()));
let (command_span, script) = iter.expect_literal()?;
iter.expect_done()?;
Self { name_span, name: VarName(name), command: script.to_string(), initial_value, command_span }
};
result.note(r#"Expected format: `(deflisten name :initial "0" "tail -f /tmp/example")`"#)
}
}