makepad_platform/
live_cx.rs

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           /*LiveToken,*/
16            LivePtr,
17            /*LiveTokenId,*/
18            LiveFileId,
19        },
20        studio::{StudioToAppVec,StudioToApp},
21        web_socket::WebSocketMessage,
22        makepad_live_compiler::LiveTypeInfo,
23        /*makepad_math::*,*/
24        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    /*
102    pub fn apply_error_wrong_expression_type_for_primitive(&mut self, origin: LiveErrorOrigin, index: usize, nodes: &[LiveNode], prim: &str, b: LiveEval) {
103        self.apply_error(origin, index, nodes, format!("wrong expression return. Prop: {} primitive: {} value: {:?}", nodes[index].id, prim, b))
104    }*/
105    
106    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        // Hacky workaround to notify users, since the widget is not supported outside of android it doens't get registered
132        #[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        // lets find the child
245        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        // lets poll our studio connection
252        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        // ok so we have a life filechange
285        // now what. now we need to 'reload' our entire live system.. how.
286        // what we can do is tokenize the entire file
287        // then find the token-slice we need
288        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                // alright we need to output the correct error
302                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    // ok so now what. now we should run the expansion
331    pub fn live_expand(&mut self) {
332        let mut errs = Vec::new();
333        let mut live_registry = self.live_registry.borrow_mut();
334        /* 
335        for file in &live_registry.live_files {
336            log!("{}. {}", file.module_id.0, file.module_id.1);        // lets expand the f'er
337        }*/
338        //let dt = crate::profile_start();
339        
340        live_registry.expand_all_documents(&mut errs);
341       //crate::profile_end!(dt);
342        
343        // lets evaluate all expressions in the main module
344       /* for file in &live_registry.live_files {
345            if file.module_id == live_registry.main_module.as_ref().unwrap().module_id{
346                println!("GOT HERE");
347            }
348        }*/
349                
350        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                //println!("Error expanding live file {}", err);
354                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        //println!("START");
397        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        //println!("END");
406        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    /*
426    fn update_buffer_from_live_value(slots: usize, output: &mut [f32], offset: usize, v: &LiveValue) {
427        match slots {
428            1 => {
429                let v = v.as_float().unwrap_or(0.0) as f32;
430                output[offset + 0] = v;
431            }
432            2 => {
433                let v = v.as_vec2().unwrap_or(vec2(0.0, 0.0));
434                output[offset + 0] = v.x;
435                output[offset + 1] = v.y;
436            }
437            3 => {
438                let v = v.as_vec3().unwrap_or(vec3(0.0, 0.0, 0.0));
439                output[offset + 0] = v.x;
440                output[offset + 1] = v.y;
441                output[offset + 2] = v.z;
442            }
443            4 => {
444                let v = v.as_vec4().unwrap_or(vec4(0.0, 0.0, 0.0, 0.0));
445                output[offset + 0] = v.x;
446                output[offset + 1] = v.y;
447                output[offset + 2] = v.z;
448                output[offset + 3] = v.w;
449            }
450            _ => {
451            }
452        }
453    }
454    
455    fn update_buffer_from_live_token(slots: usize, output: &mut [f32], offset: usize, v: &LiveToken) {
456        match slots {
457            1 => {
458                let v = v.as_float().unwrap_or(0.0) as f32;
459                output[offset + 0] = v;
460            }
461            4 => {
462                let v = v.as_vec4().unwrap_or(vec4(0.0, 0.0, 0.0, 0.0));
463                output[offset + 0] = v.x;
464                output[offset + 1] = v.y;
465                output[offset + 2] = v.z;
466                output[offset + 3] = v.w;
467            }
468            _ => {
469            }
470        }
471    }*/
472    /*
473    pub fn update_shader_tables_with_live_edit(&mut self, mutated_tokens: &[LiveTokenId], live_ptrs: &[LivePtr]) -> bool {
474        // OK now.. we have to access our token tables
475        let mut change = false;
476        let live_registry_rc = self.live_registry.clone();
477        let live_registry = live_registry_rc.borrow();
478        //println!("{:?}", live_ptrs);
479        
480        for shader in &mut self.draw_shaders.shaders {
481            let mapping = &mut shader.mapping;
482            for live_ptr in live_ptrs {
483                if let Some(input) = mapping.live_uniforms.inputs.iter().find( | input | input.live_ptr == Some(*live_ptr)) {
484                    let node = live_registry.ptr_to_node(*live_ptr);
485                    Self::update_buffer_from_live_value(input.slots, &mut mapping.live_uniforms_buf, input.offset, &node.value);
486                    change = true;
487                }
488            }
489            for token_id in mutated_tokens {
490                if let Some(table_item) = mapping.const_table.table_index.get(token_id) {
491                    let doc = live_registry.token_id_to_origin_doc(*token_id);
492                    let token = &doc.tokens[token_id.token_index()];
493                    
494                    Self::update_buffer_from_live_token(table_item.slots, &mut mapping.const_table.table, table_item.offset, token);
495                    change = true;
496                }
497            }
498            
499        }
500        change
501    }
502    */
503    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}