Skip to main content

only_syntax/
builtin.rs

1//! Typed definitions for the built-in Only language vocabulary.
2//!
3//! Parsers and higher layers keep unknown names in the `Unknown` variants so
4//! diagnostics can report the original spelling without duplicating string
5//! tables across the workspace.
6
7use std::fmt;
8
9use smol_str::SmolStr;
10
11pub const GROUP_KEYWORD: &str = "group";
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash)]
14pub enum MetadataKind {
15    Help,
16    Desc,
17    Pass,
18    Fail,
19    Unknown(SmolStr),
20}
21
22impl MetadataKind {
23    pub const SUPPORTED: &'static [Self] = &[Self::Help, Self::Desc, Self::Pass, Self::Fail];
24
25    pub fn parse(name: &str) -> Self {
26        match name {
27            "help" => Self::Help,
28            "desc" => Self::Desc,
29            "pass" => Self::Pass,
30            "fail" => Self::Fail,
31            unknown => Self::Unknown(SmolStr::new(unknown)),
32        }
33    }
34
35    pub fn as_str(&self) -> &str {
36        match self {
37            Self::Help => "help",
38            Self::Desc => "desc",
39            Self::Pass => "pass",
40            Self::Fail => "fail",
41            Self::Unknown(name) => name,
42        }
43    }
44
45    pub fn is_supported(&self) -> bool {
46        !matches!(self, Self::Unknown(_))
47    }
48
49    pub fn is_result_message(&self) -> bool {
50        matches!(self, Self::Pass | Self::Fail)
51    }
52
53    pub fn description(&self) -> Option<&'static str> {
54        match self {
55            Self::Help => Some("Sets the short task or group summary."),
56            Self::Desc => Some("Adds details shown in task help."),
57            Self::Pass => Some("Shown when a task succeeds."),
58            Self::Fail => Some("Shown when a task fails."),
59            Self::Unknown(_) => None,
60        }
61    }
62
63    pub fn expected_list() -> &'static str {
64        "help, desc, pass, or fail"
65    }
66}
67
68impl fmt::Display for MetadataKind {
69    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
70        formatter.write_str(self.as_str())
71    }
72}
73
74#[derive(Debug, Clone, PartialEq, Eq, Hash)]
75pub enum DirectiveKind {
76    Version,
77    Var,
78    Shell,
79    Unknown(SmolStr),
80}
81
82impl DirectiveKind {
83    pub const SUPPORTED: &'static [Self] = &[Self::Version, Self::Var, Self::Shell];
84
85    pub fn parse(name: &str) -> Self {
86        match name {
87            "version" => Self::Version,
88            "var" => Self::Var,
89            "shell" => Self::Shell,
90            unknown => Self::Unknown(SmolStr::new(unknown)),
91        }
92    }
93
94    pub fn as_str(&self) -> &str {
95        match self {
96            Self::Version => "version",
97            Self::Var => "var",
98            Self::Shell => "shell",
99            Self::Unknown(name) => name,
100        }
101    }
102
103    pub fn is_supported(&self) -> bool {
104        !matches!(self, Self::Unknown(_))
105    }
106
107    pub fn description(&self) -> Option<&'static str> {
108        match self {
109            Self::Version => {
110                Some("Declares the minimum Onlyfile language capability required by this file.")
111            }
112            Self::Var => Some("Defines a global string value."),
113            Self::Shell => Some("Sets the default shell used for task commands."),
114            Self::Unknown(_) => None,
115        }
116    }
117}
118
119impl fmt::Display for DirectiveKind {
120    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
121        formatter.write_str(self.as_str())
122    }
123}
124
125#[derive(Debug, Clone, PartialEq, Eq, Hash)]
126pub enum GuardKind {
127    Os,
128    Arch,
129    Env,
130    Has,
131    Unknown(SmolStr),
132}
133
134impl GuardKind {
135    pub const SUPPORTED: &'static [Self] = &[Self::Os, Self::Arch, Self::Env, Self::Has];
136
137    pub fn parse(name: &str) -> Self {
138        match name {
139            "os" => Self::Os,
140            "arch" => Self::Arch,
141            "env" => Self::Env,
142            "has" => Self::Has,
143            unknown => Self::Unknown(SmolStr::new(unknown)),
144        }
145    }
146
147    pub fn as_str(&self) -> &str {
148        match self {
149            Self::Os => "os",
150            Self::Arch => "arch",
151            Self::Env => "env",
152            Self::Has => "has",
153            Self::Unknown(name) => name,
154        }
155    }
156
157    pub fn is_supported(&self) -> bool {
158        !matches!(self, Self::Unknown(_))
159    }
160
161    pub fn description(&self) -> Option<&'static str> {
162        match self {
163            Self::Os => Some("Checks the current operating system."),
164            Self::Arch => Some("Checks the current CPU architecture."),
165            Self::Env => Some("Checks whether an environment variable exists."),
166            Self::Has => Some("Checks whether a command is available."),
167            Self::Unknown(_) => None,
168        }
169    }
170}
171
172impl fmt::Display for GuardKind {
173    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
174        formatter.write_str(self.as_str())
175    }
176}
177
178#[derive(Debug, Clone, PartialEq, Eq)]
179pub enum ShellKind {
180    Deno,
181    Bash,
182    Sh,
183    Pwsh,
184    Powershell,
185    Unknown(SmolStr),
186}
187
188impl ShellKind {
189    pub const SUPPORTED: &'static [Self] = &[
190        Self::Deno,
191        Self::Bash,
192        Self::Sh,
193        Self::Pwsh,
194        Self::Powershell,
195    ];
196
197    pub fn parse(name: &str) -> Self {
198        match name {
199            "deno" => Self::Deno,
200            "bash" => Self::Bash,
201            "sh" => Self::Sh,
202            "pwsh" => Self::Pwsh,
203            "powershell" => Self::Powershell,
204            unknown => Self::Unknown(SmolStr::new(unknown)),
205        }
206    }
207
208    pub fn as_str(&self) -> &str {
209        match self {
210            Self::Deno => "deno",
211            Self::Bash => "bash",
212            Self::Sh => "sh",
213            Self::Pwsh => "pwsh",
214            Self::Powershell => "powershell",
215            Self::Unknown(name) => name,
216        }
217    }
218
219    pub fn fallback(&self) -> Option<Self> {
220        match self {
221            Self::Pwsh => Some(Self::Powershell),
222            Self::Bash => Some(Self::Sh),
223            _ => None,
224        }
225    }
226
227    pub fn is_supported(&self) -> bool {
228        !matches!(self, Self::Unknown(_))
229    }
230
231    pub fn description(&self) -> Option<&'static str> {
232        match self {
233            Self::Deno => Some("Runs commands with Deno."),
234            Self::Bash => Some("Runs commands with Bash."),
235            Self::Sh => Some("Runs commands with the system sh."),
236            Self::Pwsh => Some("Runs commands with PowerShell Core."),
237            Self::Powershell => Some("Runs commands with Windows PowerShell."),
238            Self::Unknown(_) => None,
239        }
240    }
241}
242
243impl fmt::Display for ShellKind {
244    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
245        formatter.write_str(self.as_str())
246    }
247}
248
249#[derive(Debug, Clone, Copy, PartialEq, Eq)]
250pub enum ShellOperator {
251    Required,
252    Fallback,
253}
254
255#[derive(Debug, Clone, PartialEq, Eq)]
256pub struct ShellSelection {
257    pub kind: ShellKind,
258    pub operator: ShellOperator,
259}
260
261impl ShellSelection {
262    pub fn required(kind: ShellKind) -> Self {
263        Self {
264            kind,
265            operator: ShellOperator::Required,
266        }
267    }
268}
269
270impl ShellOperator {
271    pub fn as_str(self) -> &'static str {
272        match self {
273            Self::Required => "shell=",
274            Self::Fallback => "shell~=",
275        }
276    }
277}
278
279impl fmt::Display for ShellOperator {
280    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
281        formatter.write_str(self.as_str())
282    }
283}
284
285#[derive(Debug, Clone, PartialEq, Eq)]
286pub struct TaskShellRef {
287    pub selection: ShellSelection,
288    pub range: text_size::TextRange,
289}