src/Builder4/Editor.bjs
[app.Builder.js] / src / Builder4 / Editor.vala
1 static Editor  _Editor;
2
3 public class Editor : Object
4 {
5     public Gtk.Box el;
6     private Editor  _this;
7
8     public static Editor singleton()
9     {
10         if (_Editor == null) {
11             _Editor= new Editor();
12         }
13         return _Editor;
14     }
15     public Xcls_save_button save_button;
16     public Xcls_key_edit key_edit;
17     public Xcls_RightEditor RightEditor;
18     public Xcls_view view;
19     public Xcls_buffer buffer;
20
21         // my vars (def)
22     public Xcls_MainWindow window;
23     public string activeEditor;
24     public int pos_root_x;
25     public int pos_root_y;
26     public string ptype;
27     public string key;
28     public JsRender.JsRender file;
29     public bool pos;
30     public bool dirty;
31     public string fname;
32     public signal void save ();
33     public JsRender.Node node;
34
35     // ctor
36     public Editor()
37     {
38         _this = this;
39         this.el = new Gtk.Box( Gtk.Orientation.VERTICAL, 0 );
40
41         // my vars (dec)
42         this.window = null;
43         this.activeEditor = "";
44         this.ptype = "";
45         this.key = "";
46         this.file = null;
47         this.pos = false;
48         this.dirty = false;
49         this.node = null;
50
51         // set gobject values
52         this.el.homogeneous = false;
53         this.el.expand = true;
54         var child_0 = new Xcls_Box2( _this );
55         child_0.ref();
56         this.el.pack_start (  child_0.el , false,true );
57         var child_1 = new Xcls_RightEditor( _this );
58         child_1.ref();
59         this.el.pack_end (  child_1.el , true,true );
60
61         // init method
62
63         {
64             this.fname = "";
65         }
66     }
67
68     // user defined functions
69     public   bool saveContents ()  {
70         
71         
72         
73         
74         
75         
76         
77        
78          
79          var str = _this.buffer.toString();
80          
81           
82          
83          
84          if (!_this.buffer.checkSyntax()) {
85              print("check syntax failed");
86              //this.get('/StandardErrorDialog').show("Fix errors in code and save.."); 
87              //return false;
88          }
89          
90          // LeftPanel.model.changed(  str , false);
91          _this.dirty = false;
92          _this.save_button.el.sensitive = false;
93          
94          
95             
96          
97         // find the text for the node..
98         if (ptype == "listener") {
99             this.node.listeners.set(key,str);
100         
101         } else {
102              this.node.props.set(key,str);
103         }
104     
105          
106         
107         // call the signal..
108         this.save();
109         
110         return true;
111     
112     }
113     public void showPlainFile (string fname)
114     {
115         this.ptype = "";
116         this.key  = "";
117         this.node = null;
118         this.file = null;
119         this.fname = fname;
120         string str;
121         try {
122             GLib.FileUtils.get_contents(fname, out str);
123         } catch (Error e) {
124             str = ""; // a tad dangerios... - perhaps we should block editing...
125         }
126         
127         this.view.load(str);
128         this.key_edit.el.text = "";    
129     
130     }
131     public   void show (JsRender.JsRender file, JsRender.Node node, string ptype, string key)
132     {
133         this.ptype = ptype;
134         this.key  = key;
135         this.node = node;
136         this.file = file;
137         
138        string val = "";
139         // find the text for the node..
140         if (ptype == "listener") {
141             val = node.listeners.get(key);
142         
143         } else {
144             val = node.props.get(key);
145         }
146         this.view.load(val);
147         this.key_edit.el.text = key;    
148     
149     }
150     public class Xcls_Box2 : Object
151     {
152         public Gtk.Box el;
153         private Editor  _this;
154
155
156             // my vars (def)
157
158         // ctor
159         public Xcls_Box2(Editor _owner )
160         {
161             _this = _owner;
162             this.el = new Gtk.Box( Gtk.Orientation.HORIZONTAL, 0 );
163
164             // my vars (dec)
165
166             // set gobject values
167             this.el.homogeneous = false;
168             var child_0 = new Xcls_save_button( _this );
169             child_0.ref();
170             this.el.pack_start (  child_0.el , false,false );
171             var child_1 = new Xcls_key_edit( _this );
172             child_1.ref();
173             this.el.pack_end (  child_1.el , true,true );
174         }
175
176         // user defined functions
177     }
178     public class Xcls_save_button : Object
179     {
180         public Gtk.Button el;
181         private Editor  _this;
182
183
184             // my vars (def)
185
186         // ctor
187         public Xcls_save_button(Editor _owner )
188         {
189             _this = _owner;
190             _this.save_button = this;
191             this.el = new Gtk.Button();
192
193             // my vars (dec)
194
195             // set gobject values
196             this.el.label = "Save";
197
198             //listeners
199             this.el.clicked.connect( () => { 
200                 _this.saveContents();
201             });
202         }
203
204         // user defined functions
205     }
206
207     public class Xcls_key_edit : Object
208     {
209         public Gtk.Entry el;
210         private Editor  _this;
211
212
213             // my vars (def)
214
215         // ctor
216         public Xcls_key_edit(Editor _owner )
217         {
218             _this = _owner;
219             _this.key_edit = this;
220             this.el = new Gtk.Entry();
221
222             // my vars (dec)
223
224             // set gobject values
225         }
226
227         // user defined functions
228     }
229
230
231     public class Xcls_RightEditor : Object
232     {
233         public Gtk.ScrolledWindow el;
234         private Editor  _this;
235
236
237             // my vars (def)
238
239         // ctor
240         public Xcls_RightEditor(Editor _owner )
241         {
242             _this = _owner;
243             _this.RightEditor = this;
244             this.el = new Gtk.ScrolledWindow( null, null );
245
246             // my vars (dec)
247
248             // set gobject values
249             var child_0 = new Xcls_view( _this );
250             child_0.ref();
251             this.el.add (  child_0.el  );
252
253             // init method
254
255             this.el.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
256         }
257
258         // user defined functions
259     }
260     public class Xcls_view : Object
261     {
262         public Gtk.SourceView el;
263         private Editor  _this;
264
265
266             // my vars (def)
267
268         // ctor
269         public Xcls_view(Editor _owner )
270         {
271             _this = _owner;
272             _this.view = this;
273             this.el = new Gtk.SourceView();
274
275             // my vars (dec)
276
277             // set gobject values
278             this.el.auto_indent = true;
279             this.el.indent_width = 4;
280             this.el.show_line_marks = true;
281             this.el.insert_spaces_instead_of_tabs = true;
282             this.el.show_line_numbers = true;
283             this.el.highlight_current_line = true;
284             var child_0 = new Xcls_buffer( _this );
285             child_0.ref();
286             this.el.set_buffer (  child_0.el  );
287
288             // init method
289
290             var description =   Pango.FontDescription.from_string("monospace");
291                 description.set_size(8000);
292                 this.el.override_font(description);
293             
294             
295               
296                 var attrs = new Gtk.SourceMarkAttributes();
297                 var  pink =   Gdk.RGBA();
298                 pink.parse ( "pink");
299                 attrs.set_background ( pink);
300                 attrs.set_icon_name ( "process-stop");    
301                 attrs.query_tooltip_text.connect(( mark) => {
302                     //print("tooltip query? %s\n", mark.name);
303                     return mark.name;
304                 });
305                 
306                 this.el.set_mark_attributes ("ERR", attrs, 1);
307                 
308                  var wattrs = new Gtk.SourceMarkAttributes();
309                 var  blue =   Gdk.RGBA();
310                 blue.parse ( "#ABF4EB");
311                 wattrs.set_background ( blue);
312                 wattrs.set_icon_name ( "process-stop");    
313                 wattrs.query_tooltip_text.connect(( mark) => {
314                     //print("tooltip query? %s\n", mark.name);
315                     return mark.name;
316                 });
317                 
318                 this.el.set_mark_attributes ("WARN", wattrs, 1);
319                 
320              
321                 
322                  var dattrs = new Gtk.SourceMarkAttributes();
323                 var  purple =   Gdk.RGBA();
324                 purple.parse ( "#EEA9FF");
325                 dattrs.set_background ( purple);
326                 dattrs.set_icon_name ( "process-stop");    
327                 dattrs.query_tooltip_text.connect(( mark) => {
328                     //print("tooltip query? %s\n", mark.name);
329                     return mark.name;
330                 });
331                 
332                 this.el.set_mark_attributes ("DEPR", dattrs, 1);
333
334             //listeners
335             this.el.key_release_event.connect( (event) => {
336                 
337                 if (event.keyval == 115 && (event.state & Gdk.ModifierType.CONTROL_MASK ) > 0 ) {
338                     print("SAVE: ctrl-S  pressed");
339                     _this.saveContents();
340                     return false;
341                 }
342                // print(event.key.keyval)
343                 
344                 return false;
345             
346             });
347         }
348
349         // user defined functions
350         public   void load (string str) {
351         
352         // show the help page for the active node..
353            //this.get('/Help').show();
354         
355         
356           // this.get('/BottomPane').el.set_current_page(0);
357             var buf = (Gtk.SourceBuffer)this.el.get_buffer();
358             buf.set_text(str, str.length);
359             buf.set_undo_manager(null);
360             
361             var lm = Gtk.SourceLanguageManager.get_default();
362             
363             var lang = "vala";    
364             if (_this.file != null) {
365                  lang = _this.file.language;
366             }  
367             //?? is javascript going to work as js?
368             
369             ((Gtk.SourceBuffer)(this.el.get_buffer())) .set_language(lm.get_language(lang));
370          
371              
372             _this.dirty = false;
373             this.el.grab_focus();
374             _this.save_button.el.sensitive = false;
375         }
376     }
377     public class Xcls_buffer : Object
378     {
379         public Gtk.SourceBuffer el;
380         private Editor  _this;
381
382
383             // my vars (def)
384         public bool check_queued;
385         public int error_line;
386         public bool check_running;
387
388         // ctor
389         public Xcls_buffer(Editor _owner )
390         {
391             _this = _owner;
392             _this.buffer = this;
393             this.el = new Gtk.SourceBuffer( null );
394
395             // my vars (dec)
396             this.check_queued = false;
397             this.error_line = -1;
398             this.check_running = false;
399
400             // set gobject values
401
402             //listeners
403             this.el.changed.connect( () => {
404                 // check syntax??
405                 // ??needed..??
406                 _this.save_button.el.sensitive = true;
407                 print("EDITOR CHANGED");
408                 this.checkSyntax();
409                
410                 _this.dirty = true;
411             
412                 // this.get('/LeftPanel.model').changed(  str , false);
413                 return ;
414             });
415         }
416
417         // user defined functions
418         public bool highlightErrors ( Gee.HashMap<int,string> validate_res) {
419                 this.error_line = validate_res.size;
420         
421                 if (this.error_line < 1) {
422                       return true;
423                 }
424                 var tlines = this.el.get_line_count ();
425                 Gtk.TextIter iter;
426                 var valiter = validate_res.map_iterator();
427                 while (valiter.next()) {
428                 
429             //        print("get inter\n");
430                     var eline = valiter.get_key();
431                     if (eline > tlines) {
432                         continue;
433                     }
434                     this.el.get_iter_at_line( out iter, eline);
435                     //print("mark line\n");
436                     this.el.create_source_mark(valiter.get_value(), "error", iter);
437                 }   
438                 return false;
439             }
440         public   string toString () {
441             
442             Gtk.TextIter s;
443             Gtk.TextIter e;
444             this.el.get_start_iter(out s);
445             this.el.get_end_iter(out e);
446             var ret = this.el.get_text(s,e,true);
447             //print("TO STRING? " + ret);
448             return ret;
449         }
450         public   bool checkSyntax () {
451          
452             if (this.check_running) {
453                 print("Check is running\n");
454                 if (this.check_queued) { 
455                     print("Check is already queued");
456                     return true;
457                 }
458                 this.check_queued = true;
459                 print("Adding queued Check ");
460                 GLib.Timeout.add_seconds(1, () => {
461                     this.check_queued = false;
462                     
463                     this.checkSyntax();
464                     return false;
465                 });
466             
467         
468                 return true;
469             }
470            
471            
472             var p = Palete.factory(_this.file.xtype);   
473             
474             var str = this.toString();
475             
476              
477             if (this.error_line > 0) {
478                  Gtk.TextIter start;
479                  Gtk.TextIter end;     
480                 this.el.get_bounds (out start, out end);
481         
482                 this.el.remove_source_marks (start, end, null);
483             }
484             
485             if (str.length < 1) {
486                 print("checkSyntax - empty string?\n");
487                 return true;
488             }
489             this.check_running = true;
490             
491             
492             if (_this.file.language == "js") {
493                 this.check_running = false;
494                 print("calling validate javascript\n"); 
495                 return this.highlightErrors(p.validateJavascript(
496                     str, 
497                      _this.key, 
498                     _this.ptype,
499                     _this.file,
500                     _this.node
501                 ));    
502                 
503             }
504                 
505                 
506             print("calling validate vala\n");    
507             // clear the buttons.
508          
509             
510             p.validateVala(
511                 _this.window.windowstate,
512                 str, 
513                  _this.key, 
514                 _this.ptype,
515                 _this.file,
516                 _this.node 
517                 
518                 
519             );
520              
521             
522             
523             //print("done mark line\n");
524              
525             return true; // at present allow saving - even if it's invalid..
526         }
527         public bool highlightErrorsJson (string type, Json.Object obj) {
528               Gtk.TextIter start;
529              Gtk.TextIter end;     
530                 this.el.get_bounds (out start, out end);
531                 
532                 this.el.remove_source_marks (start, end, type);
533                          
534              
535              // we should highlight other types of errors..
536             
537             if (!obj.has_member(type)) {
538                 print("Return has no errors\n");
539                 return true;
540             }
541             
542             if (_this.window.windowstate.state != WindowState.State.CODEONLY && 
543                 _this.window.windowstate.state != WindowState.State.CODE
544                 ) {
545                 return true;
546             } 
547             
548             if (_this.file == null) {
549                 return true;
550             }
551             
552             var err = obj.get_object_member(type);
553             
554             
555             var valafn = "";
556               try {             
557                    var  regex = new Regex("\\.bjs$");
558                 
559                  
560                     valafn = regex.replace(_this.file.path,_this.file.path.length , 0 , ".vala");
561                  } catch (GLib.RegexError e) {
562                     return true;
563                 }   
564         
565            if (!err.has_member(valafn)) {
566                 print("File path has no errors\n");
567                 return  true;
568             }
569         
570             var lines = err.get_object_member(valafn);
571             
572             var offset = 1;
573             if (obj.has_member("line_offset")) {
574                 offset = (int)obj.get_int_member("line_offset") + 1;
575             }
576              
577             
578             var tlines = this.el.get_line_count () +1;
579             
580             lines.foreach_member((obj, line, node) => {
581                 
582                      Gtk.TextIter iter;
583             //        print("get inter\n");
584                     var eline = int.parse(line) - offset;
585                     print("GOT ERROR on line %s -- converted to %d\n", line,eline);
586                     
587                     
588                     if (eline > tlines || eline < 0) {
589                         return;
590                     }
591                     this.el.get_iter_at_line( out iter, eline);
592                     //print("mark line\n");
593                     var msg  = "Line: %d".printf(eline+1);
594                     var ar = lines.get_array_member(line);
595                     for (var i = 0 ; i < ar.get_length(); i++) {
596                             msg += (msg.length > 0) ? "\n" : "";
597                             msg += ar.get_string_element(i);
598                     }
599                     
600                     
601                     this.el.create_source_mark(msg, type, iter);
602                 } );
603                 return false;
604             
605         
606         
607         
608         
609         }
610     }
611
612
613
614 }