1use {
2 crate::{
3 makepad_live_tokenizer::{LiveErrorOrigin, live_error_origin},
4 makepad_live_compiler::{
5 LiveFileChange,
6 TextPos,
7 LiveValue,
8 LiveNode,
9 LiveId,
10 LiveEval,
11 LiveProp,
12 LiveError,
13 LiveModuleId,
14 LivePtr,
16 LiveFileId,
18 },
19 makepad_error_log::*,
20 makepad_live_compiler::LiveTypeInfo,
21 cx::Cx,
23 cx::CxDependency,
24 },
25};
26
27pub struct LiveBody {
28 pub file: String,
29 pub cargo_manifest_path: String,
30 pub module_path: String,
31 pub line: usize,
32 pub column: usize,
33 pub code: String,
34 pub live_type_infos: Vec<LiveTypeInfo>
35}
36
37
38#[cfg(not(lines))]
39fn line_nr_error_once(){
40 use std::sync::atomic::{AtomicBool,Ordering};
41 static LINE_NR_ONCE: AtomicBool = AtomicBool::new(false);
42 const LINE_NR_ERROR: &'static str = "\n#############################################\n\nMakepad needs the nightly only proc_macro_span feature for accurate line information in errors\nTo install nightly use rustup:\n\nrustup install nightly\n\nPlease build your makepad application in this way on Unix:\n\nMAKEPAD=lines cargo +nightly build yourapp_etc\n\nAnd on Windows:\n\nset MAKEPAD=lines&cargo +nightly build yourapp_etc'\n\n#############################################\n";
43 if !LINE_NR_ONCE.load(Ordering::SeqCst) {
44 LINE_NR_ONCE.store(true,Ordering::SeqCst);
45 error!("{}", LINE_NR_ERROR);
46 }
47}
48
49
50impl Cx {
51
52 pub fn apply_error_tuple_enum_arg_not_found(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], enum_id: LiveId, base: LiveId, arg: usize) {
53 self.apply_error(origin, index, nodes, format!("tuple enum too many args for {}::{} arg no {}", enum_id, base, arg))
54 }
55
56 pub fn apply_error_named_enum_invalid_prop(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], enum_id: LiveId, base: LiveId, prop: LiveId) {
57 self.apply_error(origin, index, nodes, format!("named enum invalid property for {}::{} prop: {}", enum_id, base, prop))
58 }
59
60 pub fn apply_error_wrong_enum_base(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], enum_id: LiveId, base: LiveId) {
61 self.apply_error(origin, index, nodes, format!("wrong enum base expected: {} got: {}", enum_id, base))
62 }
63
64 pub fn apply_error_wrong_struct_name(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], struct_id: LiveId, got_id: LiveId) {
65 self.apply_error(origin, index, nodes, format!("wrong struct name expected: {} got: {}", struct_id, got_id))
66 }
67
68 pub fn apply_error_wrong_type_for_struct(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], struct_id: LiveId) {
69 self.apply_error(origin, index, nodes, format!("wrong type for struct: {} prop: {} type:{:?}", struct_id, nodes[index].id, nodes[index].value))
70 }
71
72 pub fn apply_error_wrong_enum_variant(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], enum_id: LiveId, variant: LiveId) {
73 self.apply_error(origin, index, nodes, format!("wrong enum variant for enum: {} got variant: {}", enum_id, variant))
74 }
75
76 pub fn apply_error_expected_enum(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode]) {
77 self.apply_error(origin, index, nodes, format!("expected enum value type, but got {} {:?}", nodes[index].id, nodes[index].value))
78 }
79
80 pub fn apply_error_expected_array(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode]) {
81 self.apply_error(origin, index, nodes, format!("expected array, but got {} {:?}", nodes[index].id, nodes[index].value))
82 }
83
84 pub fn apply_error_no_matching_field(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode]) {
85 self.apply_error(origin, index, nodes, format!("no matching field: {}", nodes[index].id))
86 }
87
88 pub fn apply_error_wrong_type_for_value(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode]) {
89 self.apply_error(origin, index, nodes, format!("wrong type for value: {}", nodes[index].id))
90 }
91
92 pub fn apply_error_component_not_found(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], id: LiveId) {
93 self.apply_error(origin, index, nodes, format!("component not found: {}", id))
94 }
95
96 pub fn apply_error_wrong_value_type_for_primitive(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], prim: &str) {
97 self.apply_error(origin, index, nodes, format!("wrong value type. Prop: {} primitive: {} value: {:?}", nodes[index].id, prim, nodes[index].value))
98 }
99
100 pub fn apply_error_wrong_expression_type_for_primitive(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], prim: &str, b: LiveEval) {
101 self.apply_error(origin, index, nodes, format!("wrong expression return. Prop: {} primitive: {} value: {:?}", nodes[index].id, prim, b))
102 }
103
104 pub fn apply_error_animation_missing_state(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], track: LiveId, state_id: LiveId, ids: &[LiveProp]) {
105 self.apply_error(origin, index, nodes, format!("animation missing animator: {} {} {:?}", track, state_id, ids))
106 }
107
108 pub fn apply_error_wrong_animation_track_used(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], id: LiveId, expect: LiveId, got: LiveId) {
109 self.apply_error(origin, index, nodes, format!("encountered value [{}] with track [{}] whilst animating on track [{}]", id, expect, got))
110 }
111
112 pub fn apply_error_animate_to_unknown_track(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], id: LiveId, state_id: LiveId) {
113 self.apply_error(origin, index, nodes, format!("unknown track {} in animate_to state_id {}", id, state_id))
114 }
115
116 pub fn apply_error_empty_object(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode]) {
117 self.apply_error(origin, index, nodes, format!("Newed empty ClassName, forgot to call 'use'"))
118 }
119
120 pub fn apply_key_frame_cannot_be_interpolated(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], a: &LiveValue, b: &LiveValue) {
121 self.apply_error(origin, index, nodes, format!("key frame values cannot be interpolated {:?} {:?}", a, b))
122 }
123
124 pub fn apply_animate_missing_apply_block(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode]) {
125 self.apply_error(origin, index, nodes, format!("animate missing apply:{{}} block"))
126 }
127
128 pub fn apply_error_cant_find_target(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], id: LiveId) {
129 self.apply_error(origin, index, nodes, format!("property: {} target class not found", id))
130 }
131
132 pub fn apply_image_type_not_supported(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], path: &str) {
133 self.apply_error(origin, index, nodes, format!("Image type not supported {}", path))
134 }
135
136 pub fn apply_image_decoding_failed(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], path: &str, msg: &str) {
137 self.apply_error(origin, index, nodes, format!("Image decoding failed {} {}", path, msg))
138 }
139
140 pub fn apply_resource_not_loaded(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], path: &str, msg: &str) {
141 self.apply_error(origin, index, nodes, format!("Resource not loaded {} {}", path, msg))
142 }
143
144 pub fn apply_error_eval(&mut self, err: LiveError) {
145 let live_registry = self.live_registry.borrow();
146 error!("{}", live_registry.live_error_to_live_file_error(err));
147 }
148
149 pub fn apply_error(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], message: String) {
150 let live_registry = self.live_registry.borrow();
151 if let Some(token_id) = &nodes[index].origin.token_id() {
152 let err = LiveError {
153 origin,
154 message,
155 span: (*token_id).into()
156 };
157 #[cfg(not(lines))]
158 line_nr_error_once();
159 if std::env::args().find(|v| v == "--message-format=json").is_some(){
160 let err = live_registry.live_error_to_live_file_error(err);
161 crate::makepad_error_log::log_with_type(
162 &err.file,
163 err.span.start.line+1,
164 err.span.start.column+2,
165 err.span.end.line+1,
166 err.span.end.column+2,
167 &err.message,
168 LogType::Error
169 );
170 }
171 else {
172 error!("Apply error: {} {:?}", live_registry.live_error_to_live_file_error(err), nodes[index].value);
173 }
174 }
175 else {
176 error!("Apply without file, at index {} {} origin: {}", index, message, origin);
177 }
178 }
179
180 pub fn start_disk_live_file_watcher(&mut self, milis:u64){
181 let live_registry = self.live_registry.borrow();
182
183 let mut file_list:Vec<(String,String, Option<String>)> = Vec::new();
184 for file in &live_registry.live_files {
185 if let Some(start) = file.file_name.find("src/"){
186 let path = format!("{}/{}", file.cargo_manifest_path, &file.file_name[start..]);
187 file_list.push((path, file.file_name.clone(), None));
188 }
189 }
190 let send = self.live_file_change_sender.clone();
191 std::thread::spawn(move || loop{
192 let mut changed_files = Vec::new();
193 for (full_path, file_name, content) in &mut file_list{
194 let next = std::fs::read_to_string(&full_path);
195 if let Ok(next) = next{
196 if let Some(content_str) = content{
197 if content_str != &next{
198 crate::log!("Live reloading application: {}",file_name.clone());
199 changed_files.push(LiveFileChange{
200 file_name:file_name.clone(),
201 content: next.clone()
202 });
203 *content = Some(next);
204 }
205 }
206 else{
207 *content = Some(next);
208 }
209 }
210 }
211 if changed_files.len()>0{
212 send.send(changed_files).unwrap();
213 }
214 std::thread::sleep(std::time::Duration::from_millis(milis));
215 });
216 }
217
218 pub fn handle_live_edit(&mut self)->bool{
219 let mut all_changes = Vec::new();
224 while let Ok(changes) = self.live_file_change_receiver.try_recv(){
225 all_changes.extend(changes);
226 }
227 if all_changes.len()>0{
228 let mut live_registry = self.live_registry.borrow_mut();
229 let mut errs = Vec::new();
230 live_registry.process_file_changes(all_changes, &mut errs);
231 for err in errs {
232 if std::env::args().find(|v| v == "--message-format=json").is_some(){
234 let err = live_registry.live_error_to_live_file_error(err);
235 crate::makepad_error_log::log_with_type(
236 &err.file,
237 err.span.start.line+1,
238 err.span.start.column+2,
239 err.span.end.line+1,
240 err.span.end.column+2,
241 &err.message,
242 LogType::Error
243 );
244 continue
245 }
246 error!("check_live_file_watcher: Error expanding live file {}", err);
247 }
248 self.draw_shaders.reset_for_live_reload();
249 true
250 }
251 else{
252 false
253 }
254 }
255
256 pub fn live_expand(&mut self) {
258 let mut errs = Vec::new();
259 let mut live_registry = self.live_registry.borrow_mut();
260 live_registry.expand_all_documents(&mut errs);
265 for err in errs {
266 if std::env::args().find(|v| v == "--message-format=json").is_some(){
267 let err = live_registry.live_error_to_live_file_error(err);
268 crate::makepad_error_log::log_with_type(
269 &err.file,
270 err.span.start.line+1,
271 err.span.start.column+2,
272 err.span.end.line+1,
273 err.span.end.column+2,
274 &err.message,
275 LogType::Error
276 );
277 continue
278 }
279 error!("Error expanding live file {}", live_registry.live_error_to_live_file_error(err));
280 }
281 }
282
283 pub fn live_scan_dependencies(&mut self) {
284 let live_registry = self.live_registry.borrow();
285 for file in &live_registry.live_files {
286 for node in &file.expanded.nodes {
287 match &node.value {
288 LiveValue::Dependency(dep)=> {
289 self.dependencies.insert(dep.as_str().to_string(), CxDependency {
290 data: None
291 });
292 },
293 _ => {
294 }
295 }
296 }
297 }
298 }
299
300 pub fn register_live_body(&mut self, live_body: LiveBody) {
301 let result = self.live_registry.borrow_mut().register_live_file(
303 &live_body.file,
304 &live_body.cargo_manifest_path,
305 LiveModuleId::from_str(&live_body.module_path).unwrap(),
306 live_body.code,
307 live_body.live_type_infos,
308 TextPos {line: live_body.line as u32, column: live_body.column as u32}
309 );
310 if let Err(err) = result {
312 #[cfg(not(lines))]
313 line_nr_error_once();
314 if std::env::args().find(|v| v == "--message-format=json").is_some(){
315 crate::makepad_error_log::log_with_type(
316 &err.file,
317 err.span.start.line+1,
318 err.span.start.column+1,
319 err.span.end.line+1,
320 err.span.end.column+1,
321 &err.message,
322 LogType::Error
323 );
324 }
325 else{
326 error!("Error parsing live file {}", err);
327 }
328 }
329 }
330 pub fn get_nodes_from_live_ptr<CB>(&mut self, live_ptr: LivePtr, cb: CB)
409 where CB: FnOnce(&mut Cx, LiveFileId, usize, &[LiveNode]) -> usize {
410 let live_registry_rc = self.live_registry.clone();
411 let live_registry = live_registry_rc.borrow();
412 if !live_registry.generation_valid(live_ptr) {
413 error!("Generation invalid in get_nodes_from_live_ptr");
414 return
415 }
416 let doc = live_registry.ptr_to_doc(live_ptr);
417
418 let next_index = cb(self, live_ptr.file_id, live_ptr.index as usize, &doc.nodes);
419 if next_index <= live_ptr.index as usize + 2 {
420 self.apply_error_empty_object(live_error_origin!(), live_ptr.index as usize, &doc.nodes);
421 }
422 }
423}
424