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 = _this.file.language;
364             //?? is javascript going to work as js?
365             
366             ((Gtk.SourceBuffer)(this.el.get_buffer())) .set_language(lm.get_language(lang));
367          
368              
369             _this.dirty = false;
370             this.el.grab_focus();
371             _this.save_button.el.sensitive = false;
372         }
373     }
374     public class Xcls_buffer : Object
375     {
376         public Gtk.SourceBuffer el;
377         private Editor  _this;
378
379
380             // my vars (def)
381         public bool check_queued;
382         public int error_line;
383         public bool check_running;
384
385         // ctor
386         public Xcls_buffer(Editor _owner )
387         {
388             _this = _owner;
389             _this.buffer = this;
390             this.el = new Gtk.SourceBuffer( null );
391
392             // my vars (dec)
393             this.check_queued = false;
394             this.error_line = -1;
395             this.check_running = false;
396
397             // set gobject values
398
399             //listeners
400             this.el.changed.connect( () => {
401                 // check syntax??
402                 // ??needed..??
403                 _this.save_button.el.sensitive = true;
404                 print("EDITOR CHANGED");
405                 this.checkSyntax();
406                
407                 _this.dirty = true;
408             
409                 // this.get('/LeftPanel.model').changed(  str , false);
410                 return ;
411             });
412         }
413
414         // user defined functions
415         public bool highlightErrors ( Gee.HashMap<int,string> validate_res) {
416                 this.error_line = validate_res.size;
417         
418                 if (this.error_line < 1) {
419                       return true;
420                 }
421                 var tlines = this.el.get_line_count ();
422                 Gtk.TextIter iter;
423                 var valiter = validate_res.map_iterator();
424                 while (valiter.next()) {
425                 
426             //        print("get inter\n");
427                     var eline = valiter.get_key();
428                     if (eline > tlines) {
429                         continue;
430                     }
431                     this.el.get_iter_at_line( out iter, eline);
432                     //print("mark line\n");
433                     this.el.create_source_mark(valiter.get_value(), "error", iter);
434                 }   
435                 return false;
436             }
437         public   string toString () {
438             
439             Gtk.TextIter s;
440             Gtk.TextIter e;
441             this.el.get_start_iter(out s);
442             this.el.get_end_iter(out e);
443             var ret = this.el.get_text(s,e,true);
444             //print("TO STRING? " + ret);
445             return ret;
446         }
447         public   bool checkSyntax () {
448          
449             if (this.check_running) {
450                 print("Check is running\n");
451                 if (this.check_queued) { 
452                     print("Check is already queued");
453                     return true;
454                 }
455                 this.check_queued = true;
456                 print("Adding queued Check ");
457                 GLib.Timeout.add_seconds(1, () => {
458                     this.check_queued = false;
459                     
460                     this.checkSyntax();
461                     return false;
462                 });
463             
464         
465                 return true;
466             }
467            
468            
469             var p = Palete.factory(_this.file.xtype);   
470             
471             var str = this.toString();
472             
473              
474             if (this.error_line > 0) {
475                  Gtk.TextIter start;
476                  Gtk.TextIter end;     
477                 this.el.get_bounds (out start, out end);
478         
479                 this.el.remove_source_marks (start, end, null);
480             }
481             
482             if (str.length < 1) {
483                 print("checkSyntax - empty string?\n");
484                 return true;
485             }
486             this.check_running = true;
487             
488             
489             if (_this.file.language == "js") {
490                 this.check_running = false;
491                 print("calling validate javascript\n"); 
492                 return this.highlightErrors(p.validateJavascript(
493                     str, 
494                      _this.key, 
495                     _this.ptype,
496                     _this.file,
497                     _this.node
498                 ));    
499                 
500             }
501                 
502                 
503             print("calling validate vala\n");    
504             // clear the buttons.
505          
506             
507             p.validateVala(
508                 _this.window.windowstate,
509                 str, 
510                  _this.key, 
511                 _this.ptype,
512                 _this.file,
513                 _this.node 
514                 
515                 
516             );
517              
518             
519             
520             //print("done mark line\n");
521              
522             return true; // at present allow saving - even if it's invalid..
523         }
524         public bool highlightErrorsJson (string type, Json.Object obj) {
525               Gtk.TextIter start;
526              Gtk.TextIter end;     
527                 this.el.get_bounds (out start, out end);
528                 
529                 this.el.remove_source_marks (start, end, type);
530                          
531              
532              // we should highlight other types of errors..
533             
534             if (!obj.has_member(type)) {
535                 print("Return has no errors\n");
536                 return true;
537             }
538             
539             if (_this.window.windowstate.state != WindowState.State.CODEONLY && 
540                 _this.window.windowstate.state != WindowState.State.CODE
541                 ) {
542                 return true;
543             } 
544             
545             if (_this.file == null) {
546                 return true;
547             }
548             
549             var err = obj.get_object_member(type);
550             
551             
552             var valafn = "";
553               try {             
554                    var  regex = new Regex("\\.bjs$");
555                 
556                  
557                     valafn = regex.replace(_this.file.path,_this.file.path.length , 0 , ".vala");
558                  } catch (GLib.RegexError e) {
559                     return true;
560                 }   
561         
562            if (!err.has_member(valafn)) {
563                 print("File path has no errors\n");
564                 return  true;
565             }
566         
567             var lines = err.get_object_member(valafn);
568             
569             var offset = 1;
570             if (obj.has_member("line_offset")) {
571                 offset = (int)obj.get_int_member("line_offset") + 1;
572             }
573              
574             
575             var tlines = this.el.get_line_count () +1;
576             
577             lines.foreach_member((obj, line, node) => {
578                 
579                      Gtk.TextIter iter;
580             //        print("get inter\n");
581                     var eline = int.parse(line) - offset;
582                     print("GOT ERROR on line %s -- converted to %d\n", line,eline);
583                     
584                     
585                     if (eline > tlines || eline < 0) {
586                         return;
587                     }
588                     this.el.get_iter_at_line( out iter, eline);
589                     //print("mark line\n");
590                     var msg  = "Line: %d".printf(eline+1);
591                     var ar = lines.get_array_member(line);
592                     for (var i = 0 ; i < ar.get_length(); i++) {
593                             msg += (msg.length > 0) ? "\n" : "";
594                             msg += ar.get_string_element(i);
595                     }
596                     
597                     
598                     this.el.create_source_mark(msg, type, iter);
599                 } );
600                 return false;
601             
602         
603         
604         
605         
606         }
607     }
608
609
610
611 }