1#![doc = include_str!("README.md")]
6#![doc(html_logo_url = "https://slint.dev/logo/slint-logo-square-light.svg")]
7#![cfg_attr(docsrs, feature(doc_cfg))]
8#![deny(unsafe_code)]
10
11#[cfg(feature = "proc_macro_span")]
12extern crate proc_macro;
13
14use core::future::Future;
15use core::pin::Pin;
16use std::cell::RefCell;
17use std::collections::HashMap;
18use std::rc::Rc;
19
20pub mod builtin_macros;
21pub mod data_uri;
22pub mod diagnostics;
23pub mod doc_comments;
24pub mod embedded_resources;
25pub mod expression_tree;
26pub mod fileaccess;
27pub mod generator;
28pub mod langtype;
29pub mod layout;
30pub mod lexer;
31pub mod literals;
32pub mod llr;
33pub(crate) mod load_builtins;
34pub mod lookup;
35pub mod namedreference;
36pub mod object_tree;
37pub mod parser;
38pub mod pathutils;
39#[cfg(feature = "bundle-translations")]
40pub mod translations;
41pub mod typeloader;
42pub mod typeregister;
43
44pub mod passes;
45
46use crate::generator::OutputFormat;
47use std::path::Path;
48
49#[derive(Clone, Copy, Debug, Eq, PartialEq)]
51pub enum EmbedResourcesKind {
52 Nothing,
54 OnlyBuiltinResources,
58 ListAllResources,
62 EmbedAllResources,
65 #[cfg(feature = "software-renderer")]
66 EmbedTextures,
72}
73
74#[derive(Clone, Debug, Eq, PartialEq)]
77#[non_exhaustive]
78pub enum DefaultTranslationContext {
79 ComponentName,
83 None,
88}
89
90#[derive(Clone, Debug, Eq, PartialEq, Default)]
91#[non_exhaustive]
92pub enum ComponentSelection {
93 #[default]
99 ExportedWindows,
100
101 LastExported,
106
107 Named(String),
109}
110
111pub type OpenImportCallback =
121 Rc<dyn Fn(String) -> Pin<Box<dyn Future<Output = Option<std::io::Result<String>>>>>>;
122pub type ResourceUrlMapper = Rc<dyn Fn(&str) -> Pin<Box<dyn Future<Output = Option<String>>>>>;
123
124#[derive(Clone)]
126pub struct CompilerConfiguration {
127 pub embed_resources: EmbedResourcesKind,
130 #[cfg(all(feature = "software-renderer", feature = "sdf-fonts"))]
132 pub use_sdf_fonts: bool,
133 pub include_paths: Vec<std::path::PathBuf>,
135 pub library_paths: HashMap<String, std::path::PathBuf>,
137 pub style: Option<String>,
139
140 pub open_import_callback: Option<OpenImportCallback>,
145 pub resource_url_mapper: Option<ResourceUrlMapper>,
149
150 pub inline_all_elements: bool,
155
156 pub const_scale_factor: Option<f32>,
159
160 pub accessibility: bool,
162
163 pub enable_experimental: bool,
165
166 pub translation_domain: Option<String>,
168 #[cfg(feature = "bundle-translations")]
170 pub translation_path_bundle: Option<std::path::PathBuf>,
171 pub default_translation_context: DefaultTranslationContext,
173
174 pub no_native_menu: bool,
176
177 pub cpp_namespace: Option<String>,
179
180 pub error_on_binding_loop_with_window_layout: bool,
183
184 pub debug_info: bool,
186
187 pub debug_hooks: Option<std::hash::RandomState>,
189
190 pub components_to_generate: ComponentSelection,
191
192 pub library_name: Option<String>,
194
195 pub rust_module: Option<String>,
197
198 #[cfg(feature = "slint-sc")]
202 pub(crate) slint_sc: bool,
203}
204
205impl CompilerConfiguration {
206 pub fn new(output_format: OutputFormat) -> Self {
207 let embed_resources = if std::env::var_os("SLINT_EMBED_TEXTURES").is_some()
208 || std::env::var_os("DEP_MCU_BOARD_SUPPORT_MCU_EMBED_TEXTURES").is_some()
209 {
210 #[cfg(not(feature = "software-renderer"))]
211 panic!(
212 "the software-renderer feature must be enabled in i-slint-compiler when embedding textures"
213 );
214 #[cfg(feature = "software-renderer")]
215 EmbedResourcesKind::EmbedTextures
216 } else if let Ok(var) = std::env::var("SLINT_EMBED_RESOURCES") {
217 let var = var.parse::<bool>().unwrap_or_else(|_|{
218 panic!("SLINT_EMBED_RESOURCES has incorrect value. Must be either unset, 'true' or 'false'")
219 });
220 match var {
221 true => EmbedResourcesKind::EmbedAllResources,
222 false => EmbedResourcesKind::OnlyBuiltinResources,
223 }
224 } else {
225 match output_format {
226 #[cfg(feature = "rust")]
227 OutputFormat::Rust => EmbedResourcesKind::EmbedAllResources,
228 OutputFormat::Interpreter => EmbedResourcesKind::Nothing,
229 _ => EmbedResourcesKind::OnlyBuiltinResources,
230 }
231 };
232
233 let inline_all_elements = match std::env::var("SLINT_INLINING") {
234 Ok(var) => var.parse::<bool>().unwrap_or_else(|_| {
235 panic!(
236 "SLINT_INLINING has incorrect value. Must be either unset, 'true' or 'false'"
237 )
238 }),
239 Err(_) => output_format == OutputFormat::Interpreter,
241 };
242
243 let const_scale_factor = std::env::var("SLINT_SCALE_FACTOR")
244 .ok()
245 .and_then(|x| x.parse::<f32>().ok())
246 .filter(|f| *f > 0.);
247
248 let enable_experimental = std::env::var_os("SLINT_ENABLE_EXPERIMENTAL_FEATURES").is_some();
249
250 let debug_info = std::env::var_os("SLINT_EMIT_DEBUG_INFO").is_some();
251
252 #[cfg(feature = "slint-sc")]
253 let slint_sc = matches!(output_format, OutputFormat::SlintSc);
254
255 let cpp_namespace = match output_format {
256 #[cfg(feature = "cpp")]
257 OutputFormat::Cpp(config) => match config.namespace {
258 Some(namespace) => Some(namespace),
259 None => std::env::var("SLINT_CPP_NAMESPACE").ok(),
260 },
261 _ => None,
262 };
263
264 let style = std::env::var("SLINT_STYLE").ok();
265
266 Self {
267 embed_resources,
268 include_paths: Default::default(),
269 library_paths: Default::default(),
270 style,
271 open_import_callback: None,
272 resource_url_mapper: None,
273 inline_all_elements,
274 const_scale_factor,
275 accessibility: true,
276 enable_experimental,
277 translation_domain: None,
278 default_translation_context: DefaultTranslationContext::ComponentName,
279 no_native_menu: false,
280 cpp_namespace,
281 error_on_binding_loop_with_window_layout: false,
282 debug_info,
283 debug_hooks: None,
284 components_to_generate: ComponentSelection::ExportedWindows,
285 #[cfg(all(feature = "software-renderer", feature = "sdf-fonts"))]
286 use_sdf_fonts: false,
287 #[cfg(feature = "bundle-translations")]
288 translation_path_bundle: std::env::var("SLINT_BUNDLE_TRANSLATIONS")
289 .ok()
290 .map(|x| x.into()),
291 library_name: None,
292 rust_module: None,
293 #[cfg(feature = "slint-sc")]
294 slint_sc,
295 }
296 }
297}
298
299fn prepare_for_compile(
303 diagnostics: &mut diagnostics::BuildDiagnostics,
304 #[allow(unused_mut)] mut compiler_config: CompilerConfiguration,
305) -> typeloader::TypeLoader {
306 #[cfg(feature = "software-renderer")]
307 if compiler_config.embed_resources == EmbedResourcesKind::EmbedTextures {
308 compiler_config.accessibility = false;
311 }
312
313 diagnostics.enable_experimental = compiler_config.enable_experimental;
314 #[cfg(feature = "slint-sc")]
315 {
316 diagnostics.slint_sc = compiler_config.slint_sc;
317 }
318
319 typeloader::TypeLoader::new(compiler_config, diagnostics)
320}
321
322pub async fn compile_syntax_node(
323 doc_node: parser::SyntaxNode,
324 mut diagnostics: diagnostics::BuildDiagnostics,
325 #[allow(unused_mut)] mut compiler_config: CompilerConfiguration,
326) -> (object_tree::Document, diagnostics::BuildDiagnostics, typeloader::TypeLoader) {
327 let mut loader = prepare_for_compile(&mut diagnostics, compiler_config);
328
329 let doc_node: parser::syntax_nodes::Document = doc_node.into();
330
331 let type_registry =
332 Rc::new(RefCell::new(typeregister::TypeRegister::new(&loader.global_type_registry)));
333 let (foreign_imports, reexports) =
334 loader.load_dependencies_recursively(&doc_node, &mut diagnostics, &type_registry).await;
335
336 let ignore_missing_font_files = loader.compiler_config.resource_url_mapper.is_some();
337 let mut doc = crate::object_tree::Document::from_node(
338 doc_node,
339 foreign_imports,
340 reexports,
341 &mut diagnostics,
342 &type_registry,
343 ignore_missing_font_files,
344 );
345
346 if !diagnostics.has_errors() {
347 passes::run_passes(&mut doc, &mut loader, false, &mut diagnostics).await;
348 } else {
349 passes::run_import_passes(&doc, &loader, &mut diagnostics);
351 }
352 (doc, diagnostics, loader)
353}
354
355pub async fn load_root_file(
361 path: &Path,
362 source_path: &Path,
363 source_code: String,
364 mut diagnostics: diagnostics::BuildDiagnostics,
365 #[allow(unused_mut)] mut compiler_config: CompilerConfiguration,
366) -> (std::path::PathBuf, diagnostics::BuildDiagnostics, typeloader::TypeLoader) {
367 let mut loader = prepare_for_compile(&mut diagnostics, compiler_config);
368
369 let (path, _) =
370 loader.load_root_file(path, source_path, source_code, false, &mut diagnostics).await;
371
372 (path, diagnostics, loader)
373}
374
375pub async fn load_root_file_with_raw_type_loader(
382 path: &Path,
383 source_path: &Path,
384 source_code: String,
385 mut diagnostics: diagnostics::BuildDiagnostics,
386 #[allow(unused_mut)] mut compiler_config: CompilerConfiguration,
387) -> (
388 std::path::PathBuf,
389 diagnostics::BuildDiagnostics,
390 typeloader::TypeLoader,
391 Option<typeloader::TypeLoader>,
392) {
393 let mut loader = prepare_for_compile(&mut diagnostics, compiler_config);
394
395 let (path, raw_type_loader) =
396 loader.load_root_file(path, source_path, source_code, true, &mut diagnostics).await;
397
398 (path, diagnostics, loader, raw_type_loader)
399}