rippy_cli/config/
types.rs1use crate::condition::Condition;
2use crate::pattern::Pattern;
3use crate::verdict::Decision;
4
5use std::path::PathBuf;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum RuleTarget {
10 Command,
11 Redirect,
12 Mcp,
13 FileRead,
14 FileWrite,
15 FileEdit,
16 After,
17}
18
19#[derive(Debug, Clone)]
24pub struct Rule {
25 pub target: RuleTarget,
26 pub decision: Decision,
27 pub pattern: Pattern,
28 pub message: Option<String>,
29 pub conditions: Vec<Condition>,
30 pub command: Option<String>,
32 pub subcommand: Option<String>,
33 pub subcommands: Option<Vec<String>>,
34 pub flags: Option<Vec<String>>,
35 pub args_contain: Option<String>,
36}
37
38impl Rule {
39 #[must_use]
40 pub fn new(target: RuleTarget, decision: Decision, pattern: &str) -> Self {
41 Self {
42 target,
43 decision,
44 pattern: Pattern::new(pattern),
45 message: None,
46 conditions: vec![],
47 command: None,
48 subcommand: None,
49 subcommands: None,
50 flags: None,
51 args_contain: None,
52 }
53 }
54
55 #[must_use]
56 pub fn with_message(mut self, msg: impl Into<String>) -> Self {
57 self.message = Some(msg.into());
58 self
59 }
60
61 #[must_use]
62 pub fn with_conditions(mut self, c: Vec<Condition>) -> Self {
63 self.conditions = c;
64 self
65 }
66
67 #[must_use]
69 pub fn structured_description(&self) -> String {
70 let mut parts = Vec::new();
71 if let Some(c) = &self.command {
72 parts.push(format!("command={c}"));
73 }
74 if let Some(s) = &self.subcommand {
75 parts.push(format!("subcommand={s}"));
76 }
77 if let Some(list) = &self.subcommands {
78 parts.push(format!("subcommands=[{}]", list.join(",")));
79 }
80 if let Some(f) = &self.flags {
81 parts.push(format!("flags=[{}]", f.join(",")));
82 }
83 if let Some(a) = &self.args_contain {
84 parts.push(format!("args-contain={a}"));
85 }
86 parts.join(" ")
87 }
88
89 #[must_use]
91 pub const fn has_structured_fields(&self) -> bool {
92 self.command.is_some()
93 || self.subcommand.is_some()
94 || self.subcommands.is_some()
95 || self.flags.is_some()
96 || self.args_contain.is_some()
97 }
98
99 #[must_use]
101 pub fn action_str(&self) -> String {
102 let base = self.decision.as_str();
103 match self.target {
104 RuleTarget::Command => base.to_string(),
105 RuleTarget::Redirect => format!("{base}-redirect"),
106 RuleTarget::Mcp => format!("{base}-mcp"),
107 RuleTarget::FileRead => format!("{base}-read"),
108 RuleTarget::FileWrite => format!("{base}-write"),
109 RuleTarget::FileEdit => format!("{base}-edit"),
110 RuleTarget::After => "after".to_string(),
111 }
112 }
113}
114
115#[derive(Debug, Clone)]
117pub enum ConfigDirective {
118 Rule(Rule),
119 Set {
120 key: String,
121 value: String,
122 },
123 Alias {
124 source: String,
125 target: String,
126 },
127 CdAllow(PathBuf),
128 ProjectBoundary,
130}