1use std::{env, fs};
2
3use anyhow::Result;
4
5use crate::schema::Group;
6
7mod js_lists;
8mod js_pkgs;
9mod parser_lists;
10mod parsers_dep;
11mod parsers_git;
12mod parsers_gitdep;
13mod queries;
14mod theme_list;
15
16const TOML_AUTOGEN_HEADER: &str = "
17###########################################
18### All following code is autogenerated ###
19### by running `cargo xtask codegen` in ###
20### the syntastica workspace. #############
21###########################################
22";
23const TOML_FEATURES_HEAD: &str = r##"
24[features]
25#! ### Features
26default = []
27
28#! Every supported language has a feature with the same name as the respective public function.
29#! Additionally the three feature groups
30#! <span class="stab portability"><code>some</code></span>,
31#! <span class="stab portability"><code>most</code></span>, and
32#! <span class="stab portability"><code>all</code></span>
33#! are available.
34
35## Include parsers for the most widely known supported languages.
36"##;
37const TOML_FEATURES_MOST: &str = r##"
38## Implies <span class="stab portability"><code>some</code></span>.
39## Include parsers for most common languages.
40"##;
41const TOML_FEATURES_ALL: &str = r##"
42## Implies <span class="stab portability"><code>most</code></span>.
43## Include parsers for all supported languages.
44"##;
45const TOML_FEATURES_DOCS: &str = r##"
46## Meant to be enabled when building docs
47docs = ["dep:document-features", "dep:rustc_version"]
48
49"##;
50
51fn is_arg(test: &str) -> bool {
52 env::args().nth(2).map_or(true, |arg| arg == test)
53}
54
55pub fn run() -> Result<()> {
56 if is_arg("queries") {
57 let mut queries_lib_rs = r###"
58#![doc = include_str!("../README.md")]
59#![cfg_attr(all(doc, CHANNEL_NIGHTLY), feature(doc_auto_cfg))]
60#![cfg_attr(rustfmt, rustfmt_skip)]
61"###
62 .trim_start()
63 .to_owned();
64
65 let queries_dir = crate::WORKSPACE_DIR.join("syntastica-queries/generated_queries");
66 let _ = fs::remove_dir_all(&queries_dir);
67 fs::create_dir_all(&queries_dir)?;
68 fs::write(
69 queries_dir.join("README.md"),
70 include_str!("./codegen/generated_queries_readme.md"),
71 )?;
72
73 for (
74 ref name,
75 [highlights, injections, locals, highlights_crates_io, injections_crates_io, locals_crates_io],
76 ) in queries::make_queries()?
77 {
78 let lang_dir = queries_dir.join(name);
79 fs::create_dir(&lang_dir)?;
80
81 fs::write(lang_dir.join("highlights.scm"), highlights)?;
82 fs::write(lang_dir.join("injections.scm"), injections)?;
83 fs::write(lang_dir.join("locals.scm"), locals)?;
84 fs::write(
85 lang_dir.join("highlights_crates_io.scm"),
86 highlights_crates_io,
87 )?;
88 fs::write(
89 lang_dir.join("injections_crates_io.scm"),
90 injections_crates_io,
91 )?;
92 fs::write(lang_dir.join("locals_crates_io.scm"), locals_crates_io)?;
93
94 queries_lib_rs += &format!(
95 r###"
96pub const {lang}_HIGHLIGHTS: &str = include_str!("../generated_queries/{name}/highlights.scm");
97pub const {lang}_INJECTIONS: &str = include_str!("../generated_queries/{name}/injections.scm");
98pub const {lang}_LOCALS: &str = include_str!("../generated_queries/{name}/locals.scm");
99pub const {lang}_HIGHLIGHTS_CRATES_IO: &str = include_str!("../generated_queries/{name}/highlights_crates_io.scm");
100pub const {lang}_INJECTIONS_CRATES_IO: &str = include_str!("../generated_queries/{name}/injections_crates_io.scm");
101pub const {lang}_LOCALS_CRATES_IO: &str = include_str!("../generated_queries/{name}/locals_crates_io.scm");
102"###,
103 lang = name.to_uppercase()
104 )
105 }
106 fs::write(
107 crate::WORKSPACE_DIR.join("syntastica-queries/src/lib.rs"),
108 queries_lib_rs,
109 )?;
110 }
111
112 if is_arg("parsers-dep") {
113 parsers_dep::write()?;
114 }
115
116 if is_arg("parsers-gitdep") {
117 parsers_gitdep::write()?;
118 }
119
120 if is_arg("parsers-git") {
121 parsers_git::write()?;
122 }
123
124 if is_arg("parser-lists") {
125 parser_lists::write()?;
126 }
127
128 if is_arg("js-list") {
129 js_lists::write()?;
130 }
131
132 if is_arg("js-pkgs") {
133 js_pkgs::write()?;
134 }
135
136 if is_arg("theme-list") {
137 theme_list::write()?;
138 }
139
140 Ok(())
141}
142
143#[derive(PartialEq, Eq)]
144enum ParserCollection {
145 Git,
146 GitDep,
147 Dep,
148}
149
150fn parsers_toml_feature(group: Group) -> String {
151 let mut feature_str = format!("{group} = [\n");
152 if let Some(group) = group.next_smaller() {
153 feature_str += &format!(" \"{group}\",\n");
154 }
155 for lang in crate::LANGUAGE_CONFIG
156 .languages
157 .iter()
158 .filter(|lang| lang.group == group)
159 {
160 feature_str += " \"";
161 feature_str += &lang.name;
162 feature_str += "\",\n";
163 }
164 feature_str + "]\n"
165}
166
167fn parsers_toml_lang_features(collection: ParserCollection) -> String {
168 let mut out = String::new();
169 for lang in &crate::LANGUAGE_CONFIG.languages {
170 out += &lang.name;
171 out += " = [";
172 if collection != ParserCollection::Git
173 && lang.parser.supports(collection == ParserCollection::GitDep)
174 {
175 out += "\"dep:";
176 out += &lang.parser.package;
177 out += "\"";
178 }
179 out += "]\n";
180 }
181 out
182}
183
184fn parsers_toml_deps(toml: &mut String, git: bool) {
185 let mut added_packages = vec![];
186 for lang in crate::LANGUAGE_CONFIG
187 .languages
188 .iter()
189 .filter(|lang| lang.parser.supports(git))
190 {
191 let package = &lang.parser.package;
192 let url = &lang.parser.git.url;
193 let rev = &lang.parser.git.rev;
194
195 if added_packages.contains(&package) {
196 continue;
197 }
198 added_packages.push(package);
199
200 let dep_str = if git {
201 format!(
202 r##"
203[dependencies.{package}]
204optional = true
205git = "{url}"
206rev = "{rev}"
207"##
208 )
209 } else {
210 format!(
211 r##"
212[dependencies.{package}]
213optional = true
214version = "={version}"
215"##,
216 version = lang
217 .parser
218 .crates_io
219 .as_ref()
220 .expect("`None` is filtered above if `git` is `false`")
221 )
222 };
223 *toml += &dep_str;
224 }
225}