makepad_platform/
live_cx.rs

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           /*LiveToken,*/
15            LivePtr,
16            /*LiveTokenId,*/
17            LiveFileId,
18        },
19        makepad_error_log::*,
20        makepad_live_compiler::LiveTypeInfo,
21        /*makepad_math::*,*/
22        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        // ok so we have a life filechange
220        // now what. now we need to 'reload' our entire live system.. how.
221        // what we can do is tokenize the entire file
222        // then find the token-slice we need
223        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                // alright we need to output the correct error
233                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    // ok so now what. now we should run the expansion
257    pub fn live_expand(&mut self) {
258        let mut errs = Vec::new();
259        let mut live_registry = self.live_registry.borrow_mut();
260        /* 
261        for file in &live_registry.live_files {
262            log!("{}. {}", file.module_id.0, file.module_id.1);        // lets expand the f'er
263        }*/
264        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        //println!("START");
302        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        //println!("END");
311        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    /*
331    fn update_buffer_from_live_value(slots: usize, output: &mut [f32], offset: usize, v: &LiveValue) {
332        match slots {
333            1 => {
334                let v = v.as_float().unwrap_or(0.0) as f32;
335                output[offset + 0] = v;
336            }
337            2 => {
338                let v = v.as_vec2().unwrap_or(vec2(0.0, 0.0));
339                output[offset + 0] = v.x;
340                output[offset + 1] = v.y;
341            }
342            3 => {
343                let v = v.as_vec3().unwrap_or(vec3(0.0, 0.0, 0.0));
344                output[offset + 0] = v.x;
345                output[offset + 1] = v.y;
346                output[offset + 2] = v.z;
347            }
348            4 => {
349                let v = v.as_vec4().unwrap_or(vec4(0.0, 0.0, 0.0, 0.0));
350                output[offset + 0] = v.x;
351                output[offset + 1] = v.y;
352                output[offset + 2] = v.z;
353                output[offset + 3] = v.w;
354            }
355            _ => {
356            }
357        }
358    }
359    
360    fn update_buffer_from_live_token(slots: usize, output: &mut [f32], offset: usize, v: &LiveToken) {
361        match slots {
362            1 => {
363                let v = v.as_float().unwrap_or(0.0) as f32;
364                output[offset + 0] = v;
365            }
366            4 => {
367                let v = v.as_vec4().unwrap_or(vec4(0.0, 0.0, 0.0, 0.0));
368                output[offset + 0] = v.x;
369                output[offset + 1] = v.y;
370                output[offset + 2] = v.z;
371                output[offset + 3] = v.w;
372            }
373            _ => {
374            }
375        }
376    }*/
377    /*
378    pub fn update_shader_tables_with_live_edit(&mut self, mutated_tokens: &[LiveTokenId], live_ptrs: &[LivePtr]) -> bool {
379        // OK now.. we have to access our token tables
380        let mut change = false;
381        let live_registry_rc = self.live_registry.clone();
382        let live_registry = live_registry_rc.borrow();
383        //println!("{:?}", live_ptrs);
384        
385        for shader in &mut self.draw_shaders.shaders {
386            let mapping = &mut shader.mapping;
387            for live_ptr in live_ptrs {
388                if let Some(input) = mapping.live_uniforms.inputs.iter().find( | input | input.live_ptr == Some(*live_ptr)) {
389                    let node = live_registry.ptr_to_node(*live_ptr);
390                    Self::update_buffer_from_live_value(input.slots, &mut mapping.live_uniforms_buf, input.offset, &node.value);
391                    change = true;
392                }
393            }
394            for token_id in mutated_tokens {
395                if let Some(table_item) = mapping.const_table.table_index.get(token_id) {
396                    let doc = live_registry.token_id_to_origin_doc(*token_id);
397                    let token = &doc.tokens[token_id.token_index()];
398                    
399                    Self::update_buffer_from_live_token(table_item.slots, &mut mapping.const_table.table, table_item.offset, token);
400                    change = true;
401                }
402            }
403            
404        }
405        change
406    }
407    */
408    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