1use {
2 crate::{
3 makepad_micro_serde::*,
4 makepad_live_tokenizer::{LiveErrorOrigin, live_error_origin},
5 makepad_live_compiler::{
6 LiveFileChange,
7 TextPos,
8 LiveValue,
9 LiveNode,
10 LiveId,
11 LiveProp,
12 LiveError,
13 LiveModuleId,
14 LiveNodeSliceApi,
15 LivePtr,
17 LiveFileId,
19 },
20 studio::{StudioToAppVec,StudioToApp},
21 web_socket::WebSocketMessage,
22 makepad_live_compiler::LiveTypeInfo,
23 cx::Cx,
25 cx::CxDependency,
26 },
27};
28
29pub struct LiveBody {
30 pub file: String,
31 pub cargo_manifest_path: String,
32 pub module_path: String,
33 pub line: usize,
34 pub column: usize,
35 pub code: String,
36 pub live_type_infos: Vec<LiveTypeInfo>
37}
38
39
40#[cfg(not(lines))]
41fn line_nr_error_once(){
42 use std::sync::atomic::{AtomicBool,Ordering};
43 static LINE_NR_ONCE: AtomicBool = AtomicBool::new(false);
44 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";
45 if !LINE_NR_ONCE.load(Ordering::SeqCst) {
46 LINE_NR_ONCE.store(true,Ordering::SeqCst);
47 error!("{}", LINE_NR_ERROR);
48 }
49}
50
51
52impl Cx {
53
54 pub fn apply_error_tuple_enum_arg_not_found(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], enum_id: LiveId, base: LiveId, arg: usize) {
55 self.apply_error(origin, index, nodes, format!("tuple enum too many args for {}::{} arg no {}", enum_id, base, arg))
56 }
57
58 pub fn apply_error_named_enum_invalid_prop(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], enum_id: LiveId, base: LiveId, prop: LiveId) {
59 self.apply_error(origin, index, nodes, format!("named enum invalid property for {}::{} prop: {}", enum_id, base, prop))
60 }
61
62 pub fn apply_error_wrong_enum_base(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], enum_id: LiveId, base: LiveId) {
63 self.apply_error(origin, index, nodes, format!("wrong enum base expected: {} got: {}", enum_id, base))
64 }
65
66 pub fn apply_error_wrong_struct_name(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], struct_id: LiveId, got_id: LiveId) {
67 self.apply_error(origin, index, nodes, format!("wrong struct name expected: {} got: {}", struct_id, got_id))
68 }
69
70 pub fn apply_error_wrong_type_for_struct(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], struct_id: LiveId) {
71 self.apply_error(origin, index, nodes, format!("wrong type for struct: {} prop: {} type:{:?}", struct_id, nodes[index].id, nodes[index].value))
72 }
73
74 pub fn apply_error_wrong_enum_variant(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], enum_id: LiveId, variant: LiveId) {
75 self.apply_error(origin, index, nodes, format!("wrong enum variant for enum: {} got variant: {}", enum_id, variant))
76 }
77
78 pub fn apply_error_expected_enum(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode]) {
79 self.apply_error(origin, index, nodes, format!("expected enum value type, but got {} {:?}", nodes[index].id, nodes[index].value))
80 }
81
82 pub fn apply_error_expected_array(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode]) {
83 self.apply_error(origin, index, nodes, format!("expected array, but got {} {:?}", nodes[index].id, nodes[index].value))
84 }
85
86 pub fn apply_error_no_matching_field(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode]) {
87 self.apply_error(origin, index, nodes, format!("no matching field: {}", nodes[index].id))
88 }
89
90 pub fn apply_error_wrong_type_for_value(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode]) {
91 self.apply_error(origin, index, nodes, format!("wrong type for value: {}", nodes[index].id))
92 }
93
94 pub fn apply_error_component_not_found(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], id: LiveId) {
95 self.apply_error(origin, index, nodes, format!("component not found: {}", id))
96 }
97
98 pub fn apply_error_wrong_value_type_for_primitive(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], prim: &str) {
99 self.apply_error(origin, index, nodes, format!("wrong value type. Prop: {} primitive: {} value: {:?}", nodes[index].id, prim, nodes[index].value))
100 }
101 pub fn apply_error_animation_missing_state(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], track: LiveId, state_id: LiveId, ids: &[LiveProp]) {
107 self.apply_error(origin, index, nodes, format!("animation missing animator: {} {} {:?}", track, state_id, ids))
108 }
109
110 pub fn apply_error_wrong_animation_track_used(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], id: LiveId, expect: LiveId, got: LiveId) {
111 self.apply_error(origin, index, nodes, format!("encountered value [{}] with track [{}] whilst animating on track [{}]", id, expect, got))
112 }
113
114 pub fn apply_error_animate_to_unknown_track(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], id: LiveId, state_id: LiveId) {
115 self.apply_error(origin, index, nodes, format!("unknown track {} in animate_to state_id {}", id, state_id))
116 }
117
118 pub fn apply_error_empty_object(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode]) {
119 self.apply_error(origin, index, nodes, format!("Newed empty ClassName, forgot to call 'use'"))
120 }
121
122 pub fn apply_key_frame_cannot_be_interpolated(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], a: &LiveValue, b: &LiveValue) {
123 self.apply_error(origin, index, nodes, format!("key frame values cannot be interpolated {:?} {:?}", a, b))
124 }
125
126 pub fn apply_animate_missing_apply_block(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode]) {
127 self.apply_error(origin, index, nodes, format!("animate missing apply:{{}} block"))
128 }
129
130 pub fn apply_error_cant_find_target(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], id: LiveId) {
131 #[cfg(not(target_os = "android"))]
133 if id == crate::live_id!(video) {
134 self.apply_error(origin, index, nodes, format!("Video Player widget is currently only supported on Android"));
135 return;
136 }
137
138 self.apply_error(origin, index, nodes, format!("property: {} target class not found", id))
139 }
140
141 pub fn apply_image_type_not_supported(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], path: &str) {
142 self.apply_error(origin, index, nodes, format!("Image type not supported {}", path))
143 }
144
145 pub fn apply_image_decoding_failed(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], path: &str, msg: &str) {
146 self.apply_error(origin, index, nodes, format!("Image decoding failed {} {}", path, msg))
147 }
148
149 pub fn apply_resource_not_loaded(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], path: &str, msg: &str) {
150 self.apply_error(origin, index, nodes, format!("Resource not loaded {} {}", path, msg))
151 }
152
153 pub fn apply_error_eval(&mut self, err: LiveError) {
154 let live_registry = self.live_registry.borrow();
155 error!("{}", live_registry.live_error_to_live_file_error(err));
156 }
157
158 pub fn apply_error_resource_not_found(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], path: &str) {
159 self.apply_error(origin, index, nodes, format!("resource not found at path {}", path))
160 }
161
162 pub fn link(&mut self, from:LiveId, to:LiveId){
163 self.live_registry.borrow_mut().link(from, to);
164 }
165
166 pub fn apply_error(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], message: String) {
167 let live_registry = self.live_registry.borrow();
168 if let Some(token_id) = &nodes[index].origin.token_id() {
169 let err = LiveError {
170 origin,
171 message,
172 span: (*token_id).into()
173 };
174 #[cfg(not(lines))]
175 line_nr_error_once();
176 if std::env::args().find(|v| v == "--message-format=json").is_some(){
177 let err = live_registry.live_error_to_live_file_error(err);
178 crate::log::log_with_level(
179 &err.file,
180 err.span.start.line,
181 err.span.start.column,
182 err.span.end.line,
183 err.span.end.column,
184 err.message,
185 crate::log::LogLevel::Error
186 );
187 }
188 else {
189 error!("Apply error: {} {:?}", live_registry.live_error_to_live_file_error(err), nodes[index].value);
190 }
191 }
192 else {
193 error!("Apply without file, at index {} {} origin: {}", index, message, origin);
194 }
195 }
196
197 pub fn start_disk_live_file_watcher(&mut self, milis:u64){
198 let live_registry = self.live_registry.borrow();
199
200 let mut file_list:Vec<(String,String, Option<String>)> = Vec::new();
201 for file in &live_registry.live_files {
202 if let Some(start) = file.file_name.find("src/"){
203 let path = format!("{}/{}", file.cargo_manifest_path, &file.file_name[start..]);
204 file_list.push((path, file.file_name.clone(), None));
205 }
206 }
207 let send = self.live_file_change_sender.clone();
208 std::thread::spawn(move || loop{
209 let mut changed_files = Vec::new();
210 for (full_path, file_name, content) in &mut file_list{
211 let next = std::fs::read_to_string(&full_path);
212 if let Ok(next) = next{
213 if let Some(content_str) = content{
214 if content_str != &next{
215 crate::log!("Live reloading application: {}",file_name.clone());
216 changed_files.push(LiveFileChange{
217 file_name:file_name.clone(),
218 content: next.clone()
219 });
220 *content = Some(next);
221 }
222 }
223 else{
224 *content = Some(next);
225 }
226 }
227 }
228 if changed_files.len()>0{
229 send.send(changed_files).unwrap();
230 }
231 std::thread::sleep(std::time::Duration::from_millis(milis));
232 });
233 }
234
235 pub fn reload_ui_dsl(&mut self){
236 let send = self.live_file_change_sender.clone();
237 send.send(vec![]).ok();
238 }
239
240 pub fn set_dsl_value(&self, crate_id:LiveId, file:LiveId, node:LiveId, value:LiveValue){
241 let mut live_registry = self.live_registry.borrow_mut();
242 let file_id = live_registry.module_id_to_file_id(LiveModuleId(crate_id, file)).unwrap();
243 let file = live_registry.file_id_to_file_mut(file_id);
244 if let Some(index) = file.original.nodes.child_by_name(0, LiveProp::instance(node)){
246 file.original.nodes[index].value = value;
247 }
248 }
249
250 pub fn handle_live_edit(&mut self)->bool{
251 let mut all_changes:Vec<LiveFileChange> = Vec::new();
253 let mut actions = Vec::new();
254 if let Some(studio_socket) = &mut self.studio_web_socket{
255 while let Ok(msg) = studio_socket.try_recv(){
256 match msg {
257 WebSocketMessage::Binary(bin)=>{
258 if let Ok(data) = StudioToAppVec::deserialize_bin(&bin){
259 for data in data.0{
260 match data{
261 StudioToApp::LiveChange{file_name, content}=>{
262 all_changes.retain(|v| v.file_name != file_name);
263 all_changes.push(LiveFileChange{file_name, content})
264 }
265 StudioToApp::Screenshot(req)=>{
266 self.screenshot_requests.push(req);
267 }
268 x=>{
269 actions.push(x);
270 }
271 }
272
273 }
274 }
275 }
276 _=>()
277 }
278 }
279 }
280 for action in actions{
281 self.action(action);
282 }
283 self.handle_actions();
284 let mut reload_dsl = false;
289 while let Ok(changes) = self.live_file_change_receiver.try_recv(){
290 if changes.len() == 0{
291 reload_dsl = true;
292 }
293 all_changes.extend(changes);
294 }
295 let mut live_registry = self.live_registry.borrow_mut();
296 if all_changes.len()>0{
297 let mut errs = Vec::new();
298 live_registry.process_file_changes(all_changes, &mut errs);
299 for err in errs {
300
301 if std::env::args().find(|v| v == "--message-format=json").is_some(){
303 let err = live_registry.live_error_to_live_file_error(err);
304 crate::log::log_with_level(
305 &err.file,
306 err.span.start.line,
307 err.span.start.column,
308 err.span.end.line,
309 err.span.end.column,
310 err.message,
311 crate::log::LogLevel::Error
312 );
313 continue
314 }
315 error!("check_live_file_watcher: Error expanding live file {}", err);
316 }
317 self.draw_shaders.reset_for_live_reload();
318 true
319 }
320 else if reload_dsl{
321 live_registry.re_expand_all_files();
322 self.draw_shaders.reset_for_live_reload();
323 true
324 }
325 else{
326 false
327 }
328 }
329
330 pub fn live_expand(&mut self) {
332 let mut errs = Vec::new();
333 let mut live_registry = self.live_registry.borrow_mut();
334 live_registry.expand_all_documents(&mut errs);
341 for err in errs {
351 if std::env::args().find(|v| v == "--message-format=json").is_some(){
352 let err = live_registry.live_error_to_live_file_error(err);
353 crate::log::log_with_level(
355 &err.file,
356 err.span.start.line,
357 err.span.start.column,
358 err.span.end.line,
359 err.span.end.column,
360 err.message,
361 crate::log::LogLevel::Error
362 );
363 continue
364 }
365 println!("Error expanding live file {}", live_registry.live_error_to_live_file_error(err));
366 }
367 }
368
369 pub fn live_scan_dependencies(&mut self) {
370 let live_registry = self.live_registry.borrow();
371 for file in &live_registry.live_files {
372 if file.module_id == live_registry.main_module.as_ref().unwrap().module_id{
373 for node in &file.expanded.nodes {
374 match &node.value {
375 LiveValue::Dependency(dep)=> {
376 self.dependencies.insert(dep.as_str().to_string(), CxDependency {
377 data: None
378 });
379 },
380 LiveValue::Font(font)=>{
381 for path in &*font.paths{
382 self.dependencies.insert(path.as_str().to_string(), CxDependency {
383 data: None
384 });
385 }
386 }
387 _ => {
388 }
389 }
390 }
391 }
392 }
393 }
394
395 pub fn register_live_body(&mut self, live_body: LiveBody) {
396 let result = self.live_registry.borrow_mut().register_live_file(
398 &live_body.file,
399 &live_body.cargo_manifest_path,
400 LiveModuleId::from_str(&live_body.module_path).unwrap(),
401 live_body.code,
402 live_body.live_type_infos,
403 TextPos {line: live_body.line as u32, column: live_body.column as u32}
404 );
405 if let Err(err) = result {
407 #[cfg(not(lines))]
408 line_nr_error_once();
409 if std::env::args().find(|v| v == "--message-format=json").is_some(){
410 crate::log::log_with_level(
411 &err.file,
412 err.span.start.line,
413 err.span.start.column,
414 err.span.end.line,
415 err.span.end.column,
416 err.message,
417 crate::log::LogLevel::Error
418 );
419 }
420 else{
421 error!("Error parsing live file {}", err);
422 }
423 }
424 }
425 pub fn get_nodes_from_live_ptr<CB>(&mut self, live_ptr: LivePtr, cb: CB)
504 where CB: FnOnce(&mut Cx, LiveFileId, usize, &[LiveNode]) -> usize {
505 let live_registry_rc = self.live_registry.clone();
506 let live_registry = live_registry_rc.borrow();
507 if !live_registry.generation_valid(live_ptr) {
508 error!("Generation invalid in get_nodes_from_live_ptr");
509 return
510 }
511 let doc = live_registry.ptr_to_doc(live_ptr);
512
513 let next_index = cb(self, live_ptr.file_id, live_ptr.index as usize, &doc.nodes);
514 if next_index <= live_ptr.index as usize + 1 {
515 self.apply_error_empty_object(live_error_origin!(), live_ptr.index as usize, &doc.nodes);
516 }
517 }
518}