Skip to main content

par_term_config/
automation.rs

1//! Configuration types for triggers and coprocesses.
2
3use serde::{Deserialize, Serialize};
4
5/// A trigger definition that matches terminal output and fires actions.
6#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
7pub struct TriggerConfig {
8    pub name: String,
9    pub pattern: String,
10    #[serde(default = "crate::defaults::bool_true")]
11    pub enabled: bool,
12    #[serde(default)]
13    pub actions: Vec<TriggerActionConfig>,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
17#[serde(tag = "type", rename_all = "snake_case")]
18pub enum TriggerActionConfig {
19    Highlight {
20        #[serde(default)]
21        fg: Option<[u8; 3]>,
22        #[serde(default)]
23        bg: Option<[u8; 3]>,
24        #[serde(default = "default_highlight_duration")]
25        duration_ms: u64,
26    },
27    Notify {
28        title: String,
29        message: String,
30    },
31    MarkLine {
32        #[serde(default)]
33        label: Option<String>,
34        #[serde(default)]
35        color: Option<[u8; 3]>,
36    },
37    SetVariable {
38        name: String,
39        value: String,
40    },
41    RunCommand {
42        command: String,
43        #[serde(default)]
44        args: Vec<String>,
45    },
46    PlaySound {
47        #[serde(default)]
48        sound_id: String,
49        #[serde(default = "default_volume")]
50        volume: u8,
51    },
52    SendText {
53        text: String,
54        #[serde(default)]
55        delay_ms: u64,
56    },
57}
58
59/// Policy for restarting a coprocess when it exits
60#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
61#[serde(rename_all = "snake_case")]
62pub enum RestartPolicy {
63    /// Never restart (default)
64    #[default]
65    Never,
66    /// Always restart regardless of exit code
67    Always,
68    /// Restart only on non-zero exit code
69    OnFailure,
70}
71
72impl RestartPolicy {
73    /// All available restart policies for UI dropdowns
74    pub fn all() -> &'static [RestartPolicy] {
75        &[Self::Never, Self::Always, Self::OnFailure]
76    }
77
78    /// Human-readable display name
79    pub fn display_name(self) -> &'static str {
80        match self {
81            Self::Never => "Never",
82            Self::Always => "Always",
83            Self::OnFailure => "On Failure",
84        }
85    }
86
87    /// Convert to core library RestartPolicy
88    pub fn to_core(self) -> par_term_emu_core_rust::coprocess::RestartPolicy {
89        match self {
90            Self::Never => par_term_emu_core_rust::coprocess::RestartPolicy::Never,
91            Self::Always => par_term_emu_core_rust::coprocess::RestartPolicy::Always,
92            Self::OnFailure => par_term_emu_core_rust::coprocess::RestartPolicy::OnFailure,
93        }
94    }
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
98pub struct CoprocessDefConfig {
99    pub name: String,
100    pub command: String,
101    #[serde(default)]
102    pub args: Vec<String>,
103    #[serde(default)]
104    pub auto_start: bool,
105    #[serde(default = "crate::defaults::bool_true")]
106    pub copy_terminal_output: bool,
107    #[serde(default)]
108    pub restart_policy: RestartPolicy,
109    #[serde(default)]
110    pub restart_delay_ms: u64,
111}
112
113fn default_highlight_duration() -> u64 {
114    5000
115}
116
117fn default_volume() -> u8 {
118    50
119}
120
121impl TriggerActionConfig {
122    /// Convert to core library TriggerAction
123    pub fn to_core_action(&self) -> par_term_emu_core_rust::terminal::TriggerAction {
124        use par_term_emu_core_rust::terminal::TriggerAction;
125        match self.clone() {
126            Self::Highlight {
127                fg,
128                bg,
129                duration_ms,
130            } => TriggerAction::Highlight {
131                fg: fg.map(|c| (c[0], c[1], c[2])),
132                bg: bg.map(|c| (c[0], c[1], c[2])),
133                duration_ms,
134            },
135            Self::Notify { title, message } => TriggerAction::Notify { title, message },
136            Self::MarkLine { label, color } => TriggerAction::MarkLine {
137                label,
138                color: color.map(|c| (c[0], c[1], c[2])),
139            },
140            Self::SetVariable { name, value } => TriggerAction::SetVariable { name, value },
141            Self::RunCommand { command, args } => TriggerAction::RunCommand { command, args },
142            Self::PlaySound { sound_id, volume } => TriggerAction::PlaySound { sound_id, volume },
143            Self::SendText { text, delay_ms } => TriggerAction::SendText { text, delay_ms },
144        }
145    }
146}