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 StudioToApp::KeepAlive=>{}
269 x=>{
270 actions.push(x);
271 }
272 }
273
274 }
275 }
276 }
277 _=>()
278 }
279 }
280 }
281 for action in actions{
282 self.action(action);
283 }
284 self.handle_actions();
285 let mut reload_dsl = false;
290 while let Ok(changes) = self.live_file_change_receiver.try_recv(){
291 if changes.len() == 0{
292 reload_dsl = true;
293 }
294 all_changes.extend(changes);
295 }
296 let mut live_registry = self.live_registry.borrow_mut();
297 if all_changes.len()>0{
298 let mut errs = Vec::new();
299 live_registry.process_file_changes(all_changes, &mut errs);
300 for err in errs {
301
302 if std::env::args().find(|v| v == "--message-format=json").is_some(){
304 let err = live_registry.live_error_to_live_file_error(err);
305 crate::log::log_with_level(
306 &err.file,
307 err.span.start.line,
308 err.span.start.column,
309 err.span.end.line,
310 err.span.end.column,
311 err.message,
312 crate::log::LogLevel::Error
313 );
314 continue
315 }
316 error!("check_live_file_watcher: Error expanding live file {}", err);
317 }
318 self.draw_shaders.reset_for_live_reload();
319 true
320 }
321 else if reload_dsl{
322 live_registry.re_expand_all_files();
323 self.draw_shaders.reset_for_live_reload();
324 true
325 }
326 else{
327 false
328 }
329 }
330
331 pub fn live_expand(&mut self) {
333 let mut errs = Vec::new();
334 let mut live_registry = self.live_registry.borrow_mut();
335 live_registry.expand_all_documents(&mut errs);
342 for err in errs {
352 if std::env::args().find(|v| v == "--message-format=json").is_some(){
353 let err = live_registry.live_error_to_live_file_error(err);
354 crate::log::log_with_level(
356 &err.file,
357 err.span.start.line,
358 err.span.start.column,
359 err.span.end.line,
360 err.span.end.column,
361 err.message,
362 crate::log::LogLevel::Error
363 );
364 continue
365 }
366 println!("Error expanding live file {}", live_registry.live_error_to_live_file_error(err));
367 }
368 }
369
370 pub fn live_scan_dependencies(&mut self) {
371 let live_registry = self.live_registry.borrow();
372 for file in &live_registry.live_files {
373 if file.module_id == live_registry.main_module.as_ref().unwrap().module_id{
374 for node in &file.expanded.nodes {
375 match &node.value {
376 LiveValue::Dependency(dep)=> {
377 self.dependencies.insert(dep.as_str().to_string(), CxDependency {
378 data: None
379 });
380 },
381 LiveValue::Font(font)=>{
382 for path in &*font.paths{
383 self.dependencies.insert(path.as_str().to_string(), CxDependency {
384 data: None
385 });
386 }
387 }
388 _ => {
389 }
390 }
391 }
392 }
393 }
394 }
395
396 pub fn register_live_body(&mut self, live_body: LiveBody) {
397 let result = self.live_registry.borrow_mut().register_live_file(
399 &live_body.file,
400 &live_body.cargo_manifest_path,
401 LiveModuleId::from_str(&live_body.module_path).unwrap(),
402 live_body.code,
403 live_body.live_type_infos,
404 TextPos {line: live_body.line as u32, column: live_body.column as u32}
405 );
406 if let Err(err) = result {
408 #[cfg(not(lines))]
409 line_nr_error_once();
410 if std::env::args().find(|v| v == "--message-format=json").is_some(){
411 crate::log::log_with_level(
412 &err.file,
413 err.span.start.line,
414 err.span.start.column,
415 err.span.end.line,
416 err.span.end.column,
417 err.message,
418 crate::log::LogLevel::Error
419 );
420 }
421 else{
422 error!("Error parsing live file {}", err);
423 }
424 }
425 }
426 pub fn get_nodes_from_live_ptr<CB>(&mut self, live_ptr: LivePtr, cb: CB)
505 where CB: FnOnce(&mut Cx, LiveFileId, usize, &[LiveNode]) -> usize {
506 let live_registry_rc = self.live_registry.clone();
507 let live_registry = live_registry_rc.borrow();
508 if !live_registry.generation_valid(live_ptr) {
509 error!("Generation invalid in get_nodes_from_live_ptr");
510 return
511 }
512 let doc = live_registry.ptr_to_doc(live_ptr);
513
514 let next_index = cb(self, live_ptr.file_id, live_ptr.index as usize, &doc.nodes);
515 if next_index <= live_ptr.index as usize + 1 {
516 self.apply_error_empty_object(live_error_origin!(), live_ptr.index as usize, &doc.nodes);
517 }
518 }
519}