1use smol_str::SmolStr;
2use text_size::TextRange;
3
4use crate::{GuardKind, ShellKind, ShellSelection};
5
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct DocumentAst {
8 pub directives: Vec<DirectiveAst>,
9 pub namespaces: Vec<NamespaceAst>,
10 pub tasks: Vec<TaskAst>,
11 pub uses_braced_namespaces: bool,
12}
13
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum DirectiveAst {
16 Version {
17 major: u64,
18 minor: u64,
19 range: TextRange,
20 },
21 Shell {
22 shell: ShellKind,
23 range: TextRange,
24 },
25 Variable {
26 name: SmolStr,
27 value: SmolStr,
28 name_range: TextRange,
29 range: TextRange,
30 },
31}
32
33#[derive(Debug, Clone, PartialEq, Eq)]
34pub struct NamespaceAst {
35 pub name: SmolStr,
36 pub doc: Option<SmolStr>,
37 pub range: TextRange,
38 pub close_range: Option<TextRange>,
39 pub is_braced: bool,
40}
41
42#[derive(Debug, Clone, PartialEq, Eq)]
43pub struct TaskAst {
44 pub name: SmolStr,
45 pub namespace: Option<SmolStr>,
46 pub doc: Option<SmolStr>,
47 pub params: Vec<ParamAst>,
48 pub guards: Vec<GuardAst>,
49 pub dependencies: Vec<DependencyAst>,
50 pub shell: Option<ShellAst>,
51 pub steps: Vec<TaskStepAst>,
52 pub range: TextRange,
53 pub uses_multiline_header: bool,
54}
55
56impl TaskAst {
57 pub fn qualified_name(&self) -> SmolStr {
58 match &self.namespace {
59 Some(namespace) => SmolStr::from(format!("{namespace}.{}", self.name)),
60 None => self.name.clone(),
61 }
62 }
63
64 pub fn signature(&self) -> SmolStr {
65 let mut signature = self.name.to_string();
66 signature.push('(');
67 signature.push_str(
68 &self
69 .params
70 .iter()
71 .map(
72 |parameter| match (parameter.is_slice, ¶meter.default_value) {
73 (true, Some(default)) => format!("{}..=\"{default}\"", parameter.name),
74 (true, None) => format!("{}..", parameter.name),
75 (false, Some(default)) => format!("{}=\"{default}\"", parameter.name),
76 (false, None) => parameter.name.to_string(),
77 },
78 )
79 .collect::<Vec<_>>()
80 .join(", "),
81 );
82 signature.push(')');
83 SmolStr::from(signature)
84 }
85
86 pub fn is_helper(&self) -> bool {
94 self.name.starts_with('_')
95 }
96}
97
98#[derive(Debug, Clone, PartialEq, Eq)]
99pub struct ParamAst {
100 pub name: SmolStr,
101 pub default_value: Option<SmolStr>,
102 pub is_slice: bool,
103 pub range: TextRange,
104}
105
106#[derive(Debug, Clone, PartialEq, Eq)]
107pub struct GuardAst {
108 pub kind: GuardKind,
109 pub argument: SmolStr,
110 pub range: TextRange,
111}
112
113#[derive(Debug, Clone, PartialEq, Eq)]
114pub struct ShellAst {
115 pub selection: ShellSelection,
116 pub range: TextRange,
117}
118
119#[derive(Debug, Clone, PartialEq, Eq)]
120pub struct DependencyAst {
121 pub name: SmolStr,
122 pub range: TextRange,
123 pub stage: usize,
124}
125
126#[derive(Debug, Clone, PartialEq, Eq)]
127pub struct CommandAst {
128 pub text: SmolStr,
129 pub interpolations: Vec<InterpolationAst>,
130 pub range: TextRange,
131}
132
133#[derive(Debug, Clone, PartialEq, Eq)]
134pub enum TaskStepAst {
135 Command(CommandAst),
136 CommandBlock(CommandBlockAst),
137}
138
139impl TaskStepAst {
140 pub fn source(&self) -> &str {
141 match self {
142 Self::Command(command) => command.text.as_str(),
143 Self::CommandBlock(block) => block.source.as_str(),
144 }
145 }
146
147 pub fn interpolations(&self) -> &[InterpolationAst] {
148 match self {
149 Self::Command(command) => &command.interpolations,
150 Self::CommandBlock(block) => &block.interpolations,
151 }
152 }
153}
154
155#[derive(Debug, Clone, PartialEq, Eq)]
156pub struct CommandBlockAst {
157 pub source: SmolStr,
158 pub interpolations: Vec<InterpolationAst>,
159 pub range: TextRange,
160 pub line_ranges: Vec<TextRange>,
161}
162
163#[derive(Debug, Clone, PartialEq, Eq)]
164pub struct InterpolationAst {
165 pub name: SmolStr,
166 pub range: TextRange,
167}