da17b3e690b17bd82f9cbbd55768804dd57f0bb0
[roobuilder] / 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_close_btn close_btn;
17         public Xcls_RightEditor RightEditor;
18         public Xcls_view view;
19         public Xcls_buffer buffer;
20         public Xcls_search_entry search_entry;
21         public Xcls_search_results search_results;
22         public Xcls_nextBtn nextBtn;
23         public Xcls_backBtn backBtn;
24         public Xcls_search_settings search_settings;
25         public Xcls_case_sensitive case_sensitive;
26         public Xcls_regex regex;
27         public Xcls_multiline multiline;
28
29                 // my vars (def)
30         public int pos_root_x;
31         public Xcls_MainWindow window;
32         public bool dirty;
33         public int pos_root_y;
34         public bool pos;
35         public int last_error_counter;
36         public GtkSource.SearchContext searchcontext;
37         public int last_search_end;
38         public signal void save ();
39         public JsRender.JsRender? file;
40         public JsRender.Node node;
41         public JsRender.NodeProp? prop;
42         public string activeEditor;
43
44         // ctor
45         public Editor()
46         {
47                 _this = this;
48                 this.el = new Gtk.Box( Gtk.Orientation.VERTICAL, 0 );
49
50                 // my vars (dec)
51                 this.window = null;
52                 this.dirty = false;
53                 this.pos = false;
54                 this.last_error_counter = 0;
55                 this.searchcontext = null;
56                 this.last_search_end = 0;
57                 this.file = null;
58                 this.node = null;
59                 this.prop = null;
60                 this.activeEditor = "";
61
62                 // set gobject values
63                 this.el.homogeneous = false;
64                 this.el.hexpand = true;
65                 this.el.vexpand = true;
66                 var child_1 = new Xcls_Box2( _this );
67                 child_1.ref();
68                 this.el.append( child_1.el );
69                 new Xcls_RightEditor( _this );
70                 this.el.append( _this.RightEditor.el );
71                 var child_3 = new Xcls_Box12( _this );
72                 child_3.ref();
73                 this.el.append ( child_3.el  );
74         }
75
76         // user defined functions
77         public bool saveContents ()  {
78             
79             
80             if (_this.file == null) {
81                 return true;
82             }
83             
84              
85              
86              var str = _this.buffer.toString();
87              
88              _this.buffer.checkSyntax();
89              
90              
91              
92              // LeftPanel.model.changed(  str , false);
93              _this.dirty = false;
94              _this.save_button.el.sensitive = false;
95              
96             // find the text for the node..
97             if (_this.file.xtype != "PlainFile") {
98                // in theory these properties have to exist!?!
99                 this.prop.val = str;
100                 //this.window.windowstate.left_props.reload();
101             } else {
102                 _this.file.setSource(  str );
103              }
104             
105             // call the signal..
106             this.save();
107             
108             return true;
109         
110         }
111         public void forwardSearch (bool change_focus) {
112         
113                 if (this.searchcontext == null) {
114                         return;
115                 } 
116         
117                 Gtk.TextIter beg, st,en;
118                  bool has_wrapped_around;
119                 this.buffer.el.get_iter_at_offset(out beg, this.last_search_end);
120                 if (!this.searchcontext.forward(beg, out st, out en, out has_wrapped_around)) {
121                 
122                         this.last_search_end = 0; // not sure if this should happen
123                 } else {
124                         if (has_wrapped_around) {
125                                 return;
126                         }
127                 
128                         this.last_search_end = en.get_offset();
129                         if (change_focus) {
130                                 this.view.el.grab_focus();
131                         }
132                         this.buffer.el.place_cursor(st);
133                         this.view.el.scroll_to_iter(st,  0.1f, true, 0.0f, 0.5f);
134                 }
135          
136         }
137         public void show (JsRender.JsRender file, JsRender.Node? node, JsRender.NodeProp? prop)
138         {
139             this.reset();
140             this.file = file;    
141             
142             if (file.xtype != "PlainFile") {
143                 this.prop = prop;
144                 this.node = node;
145         
146                 // find the text for the node..
147                 this.view.load( prop.val );
148         
149                 this.close_btn.el.show();       
150             
151             } else {
152                 this.view.load(        file.toSource() );
153                 this.close_btn.el.hide();
154             }
155          
156         }
157         public void backSearch (bool change_focus) {
158         
159                 if (this.searchcontext == null) {
160                         return;
161                 } 
162                 
163                 Gtk.TextIter beg, st,en;
164                 bool has_wrapped_around;
165                 this.buffer.el.get_iter_at_offset(out beg, this.last_search_end -1 );
166                 
167                 if (!this.searchcontext.backward(beg, out st, out en, out has_wrapped_around)) {
168                         this.last_search_end = 0;
169                 } else {
170                         this.last_search_end = en.get_offset();
171                         if (change_focus) {
172                                 this.view.el.grab_focus();
173                         }
174                         this.buffer.el.place_cursor(st);
175                         this.view.el.scroll_to_iter(st,  0.1f, true, 0.0f, 0.5f);
176                 }
177         
178         }
179         public string tempFileContents () {
180            
181            
182            if (_this.file == null) {
183                return "";
184            }
185                 var str= this.buffer.toString();
186                 if (_this.file.xtype == "PlainFile") {
187             
188                 return str;
189             
190             }
191           
192               
193              
194             GLib.debug("calling validate");    
195             // clear the buttons.
196                 if (_this.prop.name == "xns" || _this.prop.name == "xtype") {
197                         return this.file.toSource(); ;
198                 }
199                 
200                 var oldcode  = _this.prop.val;
201                 _this.prop.val = str;
202             var ret = _this.file.toSource();
203             _this.prop.val = oldcode;
204             return ret;
205             
206         }
207         public void reset () {
208                  this.file = null;    
209              
210             this.node = null;
211             this.prop = null;
212                 this.searchcontext = null;
213           
214         }
215         public int search (string in_txt) {
216         
217                 var s = new GtkSource.SearchSettings();
218                 s.case_sensitive = _this.case_sensitive.el.active;
219                 s.regex_enabled = _this.regex.el.active;        
220                 s.wrap_around = false;
221                 
222                 this.searchcontext = new GtkSource.SearchContext(this.buffer.el,s);
223                 this.searchcontext.set_highlight(true);
224                 var txt = in_txt;
225                 
226                 if (_this.multiline.el.active) {
227                         txt = in_txt.replace("\\n", "\n");
228                 }
229                 
230                 s.set_search_text(txt);
231                 Gtk.TextIter beg, st,en;
232                  
233                 this.buffer.el.get_start_iter(out beg);
234                 bool has_wrapped_around;
235                 this.searchcontext.forward(beg, out st, out en, out has_wrapped_around);
236                 this.last_search_end = 0;
237                 
238                 return this.searchcontext.get_occurrences_count();
239         
240          
241            
242         
243         }
244         public void updateErrorMarks () {
245                 
246          
247         
248                 var buf = _this.buffer.el;
249                 Gtk.TextIter start;
250                 Gtk.TextIter end;     
251                 buf.get_bounds (out start, out end);
252         
253                 
254         
255          
256                 //GLib.debug("highlight errors");                
257         
258                  // we should highlight other types of errors..
259         
260                 if (_this.window.windowstate.state != WindowState.State.CODEONLY 
261                         &&
262                         _this.window.windowstate.state != WindowState.State.CODE
263                         ) {
264                         //GLib.debug("windowstate != CODEONLY?");
265                         
266                         return;
267                 } 
268         
269                  
270                 if (_this.file == null) {
271                         GLib.debug("file is null?");
272                         return;
273         
274                 }
275                 var ar = this.file.getErrors();
276                 if (ar.size < 1) {
277                         buf.remove_source_marks (start, end, null);
278                         this.last_error_counter = file.error_counter ;
279                         //GLib.debug("highlight %s :  %s has no errors", this.file.relpath, category);
280                         return;
281                 }
282                 
283         
284          // basicaly check if there is no change, then we do not do any update..
285          // we can do this by just using an error counter?
286          // if that's changed then we will do an update, otherwise dont bother.
287                   
288                 
289                 var offset = 0;
290                 var hoffset = 0;
291         
292                 var tlines = buf.get_line_count () +1;
293                 
294                 if (_this.prop != null) {
295                         // this still seems flaky...
296         
297                         tlines = _this.prop.end_line;
298                         offset = _this.prop.start_line;
299                         hoffset = _this.node.node_pad.length;
300                         
301                          
302                 } else {
303                         // no update...
304                         if (this.last_error_counter == file.error_counter) {
305                         
306                                 return;
307                         }
308                 
309                 }
310                 buf.remove_source_marks (start, end, null);
311                 foreach(var diag in ar) { 
312                      Gtk.TextIter iter;
313         //        print("get inter\n");
314                     var eline = (int)diag.range.start.line - offset;
315                     //var eline =  diag.range.end_line - offset;
316                     //GLib.debug("GOT ERROR on line %d -- converted to %d  (offset = %d)",
317                     //  err.line ,eline, offset);
318                     
319                     
320                     if (eline > tlines || eline < 0) {
321         
322                         continue;
323                     }
324                    
325                     
326                     buf.get_iter_at_line_offset( out iter, eline, (int)diag.range.start.character - hoffset);
327                    
328                    
329                         var msg = "Line: %d %s : %s".printf(eline+1, diag.category, diag.message);
330                     buf.create_source_mark( msg, diag.category, iter);
331                    // GLib.debug("set line %d to %s", eline, msg);
332                     //this.marks.set(eline, msg);
333                 }
334                 this.last_error_counter = file.error_counter ;
335         
336         
337         
338          
339         
340         }
341         public void scroll_to_line (int line) {
342         
343                 GLib.Timeout.add(500, () => {
344            
345                         var buf = this.view.el.get_buffer();
346         
347                         var sbuf = (GtkSource.Buffer) buf;
348         
349         
350                         Gtk.TextIter iter;   
351                         sbuf.get_iter_at_line(out iter,  line);
352                         this.view.el.scroll_to_iter(iter,  0.1f, true, 0.0f, 0.5f);
353                         return false;
354                 });   
355         }
356         public class Xcls_Box2 : Object
357         {
358                 public Gtk.Box el;
359                 private Editor  _this;
360
361
362                         // my vars (def)
363
364                 // ctor
365                 public Xcls_Box2(Editor _owner )
366                 {
367                         _this = _owner;
368                         this.el = new Gtk.Box( Gtk.Orientation.HORIZONTAL, 0 );
369
370                         // my vars (dec)
371
372                         // set gobject values
373                         this.el.homogeneous = false;
374                         this.el.hexpand = true;
375                         new Xcls_save_button( _this );
376                         this.el.append( _this.save_button.el );
377                         var child_2 = new Xcls_Label4( _this );
378                         child_2.ref();
379                         this.el.append( child_2.el );
380                         var child_3 = new Xcls_Scale5( _this );
381                         child_3.ref();
382                         this.el.append( child_3.el );
383                         new Xcls_close_btn( _this );
384                         this.el.append( _this.close_btn.el );
385                 }
386
387                 // user defined functions
388         }
389         public class Xcls_save_button : Object
390         {
391                 public Gtk.Button el;
392                 private Editor  _this;
393
394
395                         // my vars (def)
396
397                 // ctor
398                 public Xcls_save_button(Editor _owner )
399                 {
400                         _this = _owner;
401                         _this.save_button = this;
402                         this.el = new Gtk.Button();
403
404                         // my vars (dec)
405
406                         // set gobject values
407                         this.el.label = "Save";
408
409                         //listeners
410                         this.el.clicked.connect( () => { 
411                             _this.saveContents();
412                         });
413                 }
414
415                 // user defined functions
416         }
417
418         public class Xcls_Label4 : Object
419         {
420                 public Gtk.Label el;
421                 private Editor  _this;
422
423
424                         // my vars (def)
425
426                 // ctor
427                 public Xcls_Label4(Editor _owner )
428                 {
429                         _this = _owner;
430                         this.el = new Gtk.Label( null );
431
432                         // my vars (dec)
433
434                         // set gobject values
435                         this.el.hexpand = true;
436                 }
437
438                 // user defined functions
439         }
440
441         public class Xcls_Scale5 : Object
442         {
443                 public Gtk.Scale el;
444                 private Editor  _this;
445
446
447                         // my vars (def)
448
449                 // ctor
450                 public Xcls_Scale5(Editor _owner )
451                 {
452                         _this = _owner;
453                         this.el = new Gtk.Scale.with_range (Gtk.Orientation.HORIZONTAL,6, 30, 1);
454
455                         // my vars (dec)
456
457                         // set gobject values
458                         this.el.width_request = 200;
459                         this.el.has_origin = true;
460                         this.el.draw_value = false;
461                         this.el.digits = 0;
462                         this.el.sensitive = true;
463
464                         // init method
465
466                         {
467                                 this.el.set_range(6,30);
468                                 this.el.set_value(8);
469                         }
470
471                         //listeners
472                         this.el.change_value.connect( (st, val ) => {
473                                  
474                                    
475                                   _this.view.css.load_from_string(
476                                                 "#editor-view { font: %dpx monospace; }".printf((int)val)
477                                    );
478                              
479                                 return false;
480                         });
481                 }
482
483                 // user defined functions
484         }
485
486         public class Xcls_close_btn : Object
487         {
488                 public Gtk.Button el;
489                 private Editor  _this;
490
491
492                         // my vars (def)
493
494                 // ctor
495                 public Xcls_close_btn(Editor _owner )
496                 {
497                         _this = _owner;
498                         _this.close_btn = this;
499                         this.el = new Gtk.Button();
500
501                         // my vars (dec)
502
503                         // set gobject values
504                         this.el.icon_name = "window-close";
505                         var child_1 = new Xcls_Image7( _this );
506                         this.el.child = child_1.el;
507
508                         //listeners
509                         this.el.clicked.connect( () => { 
510                             _this.saveContents();
511                             _this.window.windowstate.switchState(WindowState.State.PREVIEW);
512                         });
513                 }
514
515                 // user defined functions
516         }
517         public class Xcls_Image7 : Object
518         {
519                 public Gtk.Image el;
520                 private Editor  _this;
521
522
523                         // my vars (def)
524
525                 // ctor
526                 public Xcls_Image7(Editor _owner )
527                 {
528                         _this = _owner;
529                         this.el = new Gtk.Image();
530
531                         // my vars (dec)
532
533                         // set gobject values
534                         this.el.icon_name = "window-close";
535                         this.el.icon_size = Gtk.IconSize.NORMAL;
536                 }
537
538                 // user defined functions
539         }
540
541
542
543         public class Xcls_RightEditor : Object
544         {
545                 public Gtk.ScrolledWindow el;
546                 private Editor  _this;
547
548
549                         // my vars (def)
550
551                 // ctor
552                 public Xcls_RightEditor(Editor _owner )
553                 {
554                         _this = _owner;
555                         _this.RightEditor = this;
556                         this.el = new Gtk.ScrolledWindow();
557
558                         // my vars (dec)
559
560                         // set gobject values
561                         this.el.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC;
562                         this.el.vexpand = true;
563                         this.el.overlay_scrolling = false;
564                         this.el.hscrollbar_policy = Gtk.PolicyType.AUTOMATIC;
565                         new Xcls_view( _this );
566                         this.el.child = _this.view.el;
567                 }
568
569                 // user defined functions
570         }
571         public class Xcls_view : Object
572         {
573                 public GtkSource.View el;
574                 private Editor  _this;
575
576
577                         // my vars (def)
578                 public Gtk.CssProvider css;
579
580                 // ctor
581                 public Xcls_view(Editor _owner )
582                 {
583                         _this = _owner;
584                         _this.view = this;
585                         this.el = new GtkSource.View();
586
587                         // my vars (dec)
588                         this.css = null;
589
590                         // set gobject values
591                         this.el.auto_indent = true;
592                         this.el.indent_width = 4;
593                         this.el.name = "editor-view";
594                         this.el.show_line_marks = true;
595                         this.el.insert_spaces_instead_of_tabs = true;
596                         this.el.show_line_numbers = true;
597                         this.el.hexpand = true;
598                         this.el.vexpand = true;
599                         this.el.has_tooltip = true;
600                         this.el.tab_width = 4;
601                         this.el.highlight_current_line = true;
602                         new Xcls_buffer( _this );
603                         this.el.buffer = _this.buffer.el;
604                         var child_2 = new Xcls_EventControllerKey11( _this );
605                         child_2.ref();
606                         this.el.add_controller(  child_2.el );
607
608                         // init method
609
610                         this.css = new Gtk.CssProvider();
611                         
612                         this.css.load_from_string(
613                                 "#editor-view { font:  12px monospace;}"
614                         );
615                          
616                         Gtk.StyleContext.add_provider_for_display(
617                                 this.el.get_display(),
618                                 this.css,
619                                 Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
620                         );
621                                 
622                          
623                                  
624                         /*
625                         this is pretty flakey - triggers Gtk with  < 0 d
626                          var cp = new GtkSource.CompletionWords("test"); 
627                          cp.minimum_word_size  = 3;
628                          //cp.priority = 100; //?? does this do anything
629                          cp.proposals_batch_size  = 10;
630                          cp.scan_batch_size = 1000;
631                          
632                         cp.register(_this.buffer.el);
633                         this.el.completion.add_provider(cp);
634                         */
635                         this.el.completion.add_provider(new Palete.CompletionProvider(_this));
636                           
637                         //this.el.completion.unblock_interactive();
638                         this.el.completion.select_on_show = true; // select
639                         //this.el.completion.remember_info_visibility    = true;
640                         
641                         
642                         var attrs = new GtkSource.MarkAttributes();
643                         var  pink =   Gdk.RGBA();
644                         pink.parse ( "pink");
645                         attrs.set_background ( pink);
646                         attrs.set_icon_name ( "process-stop");    
647                         attrs.query_tooltip_text.connect(( mark) => {
648                              GLib.debug("tooltip query? %s", mark.name);
649                             return strdup( mark.name);
650                         });
651                          attrs.query_tooltip_markup.connect(( mark) => {
652                              GLib.debug("tooltip query? %s", mark.name);
653                             return strdup( mark.name);
654                         });
655                         this.el.set_mark_attributes ("ERR", attrs, 1);
656                         attrs.ref();
657                          var wattrs = new GtkSource.MarkAttributes();
658                         var  blue =   Gdk.RGBA();
659                         blue.parse ( "#ABF4EB");
660                         wattrs.set_background ( blue);
661                         wattrs.set_icon_name ( "process-stop");    
662                         wattrs.query_tooltip_text.connect(( mark) => {
663                              GLib.debug("tooltip query? %s", mark.name);
664                             return strdup(mark.name);
665                         });
666                         wattrs.query_tooltip_markup.connect(( mark) => {
667                              GLib.debug("tooltip query? %s", mark.name);
668                             return strdup(mark.name);
669                         });
670                         this.el.set_mark_attributes ("WARN", wattrs, 1);
671                         wattrs.ref();
672                         
673                         
674                          var dattrs = new GtkSource.MarkAttributes();
675                         var  purple =   Gdk.RGBA();
676                         purple.parse ( "#EEA9FF");
677                         dattrs.set_background ( purple);
678                         dattrs.set_icon_name ( "process-stop");    
679                         dattrs.query_tooltip_text.connect(( mark) => {
680                                 GLib.debug("tooltip query? %s", mark.name);
681                             return strdup(mark.name);
682                         });
683                         dattrs.query_tooltip_markup.connect(( mark) => {
684                                 GLib.debug("tooltip query? %s", mark.name);
685                             return strdup(mark.name);
686                         });
687                         this.el.set_mark_attributes ("DEPR", dattrs, 1);
688                         dattrs.ref();    
689                         
690                          this.el.get_space_drawer().set_matrix(null);
691                          this.el.get_space_drawer().set_types_for_locations( 
692                                 GtkSource.SpaceLocationFlags.ALL,
693                                 GtkSource.SpaceTypeFlags.ALL
694                         );
695                         this.el.get_space_drawer().set_enable_matrix(true);
696
697                         //listeners
698                         this.el.query_tooltip.connect( (x, y, keyboard_tooltip, tooltip) => {
699                                 
700                                 //GLib.debug("query tooltip");
701                                 Gtk.TextIter iter;
702                                 int trailing;
703                                 
704                                 var yoff = (int) _this.RightEditor.el.vadjustment.value;
705                                 
706                                 // I think this is problematic - if it's compliing  / updating at same time as query.
707                                 
708                                 //if (_this.window.statusbar_compile_spinner.el.spinning) {
709                                 //      return false;
710                                 //}
711                                 
712                                 this.el.get_iter_at_position (out iter, out trailing,  x,  y + yoff);
713                                  
714                                 var l = iter.get_line();
715                         
716                                 
717                                  
718                                 // GLib.debug("query tooltip line %d", (int) l);
719                                 if (l < 0) {
720                         
721                                         return false;
722                                 }
723                                 /*
724                                 if (_this.buffer.marks != null && _this.buffer.marks.has_key(l)) {
725                                         GLib.debug("line %d setting tip to %s", l,  _this.buffer.marks.get(l));
726                                         tooltip.set_text(_this.buffer.marks.get(l).dup());
727                                         return true;
728                                 }
729                          
730                                 return false;
731                                 */
732                                 
733                                   
734                                 // this crashes?? - not sure why.
735                                 var marks = _this.buffer.el.get_source_marks_at_line(l, "ERR");
736                                 if (marks.is_empty()) {
737                                         marks = _this.buffer.el.get_source_marks_at_line(l, "WARN");
738                                 }
739                                 if (marks.is_empty()) {
740                                         marks = _this.buffer.el.get_source_marks_at_line(l, "DEPR");
741                                 }
742                                 
743                                 // GLib.debug("query tooltip line %d marks %d", (int)l, (int) marks.length());
744                                 var str = "";
745                                 marks.@foreach((m) => { 
746                                         //GLib.debug("got mark %s", m.name);
747                                         str += (str.length > 0 ? "\n" : "") + m.category + ": " + m.name;
748                                 });
749                                 // true if there is a mark..
750                                 if (str.length > 0 ) {
751                                         tooltip.set_text( str );
752                                 }
753                                 return str.length > 0 ? true : false;
754                                  
755                         });
756                 }
757
758                 // user defined functions
759                 public void load (string str) {
760                 
761                 // show the help page for the active node..
762                    //this.get('/Help').show();
763                  
764                   // this.get('/BottomPane').el.set_current_page(0);
765                         GLib.debug("load called - Reset undo buffer");
766                         
767                     var buf = (GtkSource.Buffer)this.el.get_buffer();
768                     buf.begin_irreversible_action();
769                     buf.set_text(str, str.length);
770                     buf.end_irreversible_action();
771                     
772                     var lm = GtkSource.LanguageManager.get_default();
773                     var lang = "vala";
774                     if (_this.file != null) {
775                          lang = _this.file.language;
776                     }
777                     print("lang=%s, content_type = %s\n", lang, _this.file.content_type);
778                     var lg = _this.file.content_type.length > 0  ?
779                             lm.guess_language(_this.file.path, _this.file.content_type) :
780                             lm.get_language(lang);
781                      
782                    
783                     ((GtkSource.Buffer)(this.el.get_buffer())) .set_language(lg); 
784                 
785                     this.el.insert_spaces_instead_of_tabs = true;
786                     if (lg != null) {
787                                 print("sourcelanguage  = %s\n", lg.name);
788                                 if (lg.name == "Vala") {
789                                     this.el.insert_spaces_instead_of_tabs = false;
790                                 }
791                      }
792                     _this.dirty = false;
793                     this.el.grab_focus();
794                     _this.save_button.el.sensitive = false;
795                     _this.last_error_counter = -1;
796                         _this.updateErrorMarks();
797                     
798                 }
799         }
800         public class Xcls_buffer : Object
801         {
802                 public GtkSource.Buffer el;
803                 private Editor  _this;
804
805
806                         // my vars (def)
807                 public int error_line;
808                 public Gee.HashMap<int,string>? xmarks;
809                 public bool check_queued;
810
811                 // ctor
812                 public Xcls_buffer(Editor _owner )
813                 {
814                         _this = _owner;
815                         _this.buffer = this;
816                         this.el = new GtkSource.Buffer( null );
817
818                         // my vars (dec)
819                         this.error_line = -1;
820                         this.xmarks = null;
821                         this.check_queued = false;
822
823                         // set gobject values
824                         this.el.highlight_syntax = true;
825                         this.el.highlight_matching_brackets = true;
826                         this.el.enable_undo = true;
827
828                         // init method
829
830                         {
831                                 var buf = this.el;
832                                 buf.create_tag ("bold", "weight", Pango.Weight.BOLD);
833                             buf.create_tag ("type", "weight", Pango.Weight.BOLD, "foreground", "#204a87");
834                             buf.create_tag ("keyword", "weight", Pango.Weight.BOLD, "foreground", "#a40000");
835                             buf.create_tag ("text", "weight", Pango.Weight.NORMAL, "foreground", "#729fcf");
836                             buf.create_tag ("number", "weight", Pango.Weight.BOLD, "foreground", "#ad7fa8");
837                             buf.create_tag ("method", "weight", Pango.Weight.BOLD, "foreground", "#729fcf");
838                             buf.create_tag ("property", "weight", Pango.Weight.BOLD, "foreground", "#BC1F51");
839                             buf.create_tag ("variable", "weight", Pango.Weight.BOLD, "foreground", "#A518B5");
840                         
841                         }
842
843                         //listeners
844                         this.el.changed.connect( () => {
845                             // check syntax??
846                             // ??needed..??
847                             _this.save_button.el.sensitive = true;
848                             print("EDITOR CHANGED");
849                             this.checkSyntax();
850                            
851                             _this.dirty = true;
852                         
853                             // this.get('/LeftPanel.model').changed(  str , false);
854                             return ;
855                         });
856                 }
857
858                 // user defined functions
859                 public bool checkSyntax () {
860                  
861                     
862                     var str = this.toString();
863                     
864                     // needed???
865                     if (this.error_line > 0) {
866                          Gtk.TextIter start;
867                          Gtk.TextIter end;     
868                         this.el.get_bounds (out start, out end);
869                 
870                         this.el.remove_source_marks (start, end, null);
871                     }
872                     if (str.length < 1) {
873                         print("checkSyntax - empty string?\n");
874                         return true;
875                     }
876                     
877                     // bit presumptiona
878                     if (_this.file.xtype == "PlainFile") {
879                     
880                         // assume it's gtk...
881                          var  oldcode =_this.file.toSource();
882                         _this.file.setSource(str);
883                             BuilderApplication.showSpinner("appointment soon","document change pending");
884                         _this.file.getLanguageServer().document_change(_this.file);
885                 
886                         _this.file.setSource(oldcode);
887                         
888                                  
889                         return true;
890                     
891                     }
892                    if (_this.file == null) {
893                        return true;
894                    }
895                  
896                     
897                 
898                       
899                      
900                     GLib.debug("calling validate");    
901                     // clear the buttons.
902                         if (_this.prop.name == "xns" || _this.prop.name == "xtype") {
903                                 return true ;
904                         }
905                         var oldcode  = _this.prop.val;
906                         
907                         _this.prop.val = str;
908                         _this.node.updated_count++;
909                     _this.file.getLanguageServer().document_change(_this.file);
910                     _this.node.updated_count++;
911                     _this.prop.val = oldcode;
912                     
913                     
914                     //print("done mark line\n");
915                      
916                     return true; // at present allow saving - even if it's invalid..
917                 }
918                 public bool highlightErrorsJson (string type, Json.Object obj) {
919                         Gtk.TextIter start;
920                         Gtk.TextIter end;     
921                         this.el.get_bounds (out start, out end);
922                 
923                         this.el.remove_source_marks (start, end, type);
924                         GLib.debug("highlight errors");          
925                 
926                          // we should highlight other types of errors..
927                 
928                         if (!obj.has_member(type)) {
929                                 GLib.debug("Return has no errors\n");
930                                 return true;
931                         }
932                 
933                         if (_this.window.windowstate.state != WindowState.State.CODEONLY 
934                                 &&
935                                 _this.window.windowstate.state != WindowState.State.CODE
936                                 ) {
937                                 GLib.debug("windowstate != CODEONLY?");
938                                 
939                                 return true;
940                         } 
941                 
942                         //this.marks = new Gee.HashMap<int,string>();
943                         var err = obj.get_object_member(type);
944                  
945                         if (_this.file == null) {
946                                 GLib.debug("file is null?");
947                                 return true;
948                 
949                         }
950                         var valafn = _this.file.path;
951                 
952                         if (_this.file.xtype != "PlainFile") {
953                 
954                                 valafn = "";
955                                 try {             
956                                         var  regex = new Regex("\\.bjs$");
957                                         // should not happen
958                                         valafn = regex.replace(_this.file.path,_this.file.path.length , 0 , ".vala");
959                                 } catch (GLib.RegexError e) {
960                                         return true;
961                                 }   
962                 
963                 
964                 
965                         }
966                         if (!err.has_member(valafn)) {
967                                 GLib.debug("File path has no errors");
968                                 return  true;
969                         }
970                 
971                         var lines = err.get_object_member(valafn);
972                         
973                         var offset = 1;
974                         if (obj.has_member("line_offset")) { // ?? why??
975                                 offset = (int)obj.get_int_member("line_offset") + 1;
976                         }
977                 
978                 
979                         var tlines = this.el.get_line_count () +1;
980                         
981                         if (_this.prop != null) {
982                         
983                                 tlines = _this.prop.end_line + 1;
984                                 offset = _this.prop.start_line + 1;
985                         
986                         }
987                         
988                 
989                 
990                         lines.foreach_member((obj, line, node) => {
991                                 
992                              Gtk.TextIter iter;
993                 //        print("get inter\n");
994                             var eline = int.parse(line) - offset;
995                             GLib.debug("GOT ERROR on line %s -- converted to %d  (offset = %d)\n", line,eline, offset);
996                             
997                             
998                             if (eline > tlines || eline < 0) {
999                                 return;
1000                             }
1001                            
1002                             
1003                             this.el.get_iter_at_line( out iter, eline);
1004                             //print("mark line\n");
1005                             var msg  = "";
1006                             var ar = lines.get_array_member(line);
1007                             for (var i = 0 ; i < ar.get_length(); i++) {
1008                                 if (ar.get_string_element(i) == "Success") {
1009                                         continue;
1010                                 }
1011                                         msg += (msg.length > 0) ? "\n" : "";
1012                                         msg += ar.get_string_element(i);
1013                                 }
1014                                 if (msg == "") {
1015                                         return;
1016                                 }
1017                                 msg = "Line: %d".printf(eline+1) +  " " + msg;
1018                             this.el.create_source_mark(msg, type, iter);
1019                             GLib.debug("set line %d to %m", eline, msg);
1020                            // this.marks.set(eline, msg);
1021                         } );
1022                         return false;
1023                 
1024                 
1025                 
1026                 
1027                 
1028                         }
1029                 public bool highlightErrors ( Gee.HashMap<int,string> validate_res) {
1030                          
1031                         this.error_line = validate_res.size;
1032                 
1033                         if (this.error_line < 1) {
1034                                 return true;
1035                         }
1036                         var tlines = this.el.get_line_count ();
1037                         Gtk.TextIter iter;
1038                         var valiter = validate_res.map_iterator();
1039                         while (valiter.next()) {
1040                 
1041                         //        print("get inter\n");
1042                                 var eline = valiter.get_key();
1043                                 if (eline > tlines) {
1044                                         continue;
1045                                 }
1046                                 this.el.get_iter_at_line( out iter, eline);
1047                                 //print("mark line\n");
1048                                 this.el.create_source_mark(valiter.get_value(), "ERR", iter);
1049                         }   
1050                         return false;
1051                 }
1052                 public string toString () {
1053                     
1054                     Gtk.TextIter s;
1055                     Gtk.TextIter e;
1056                     this.el.get_start_iter(out s);
1057                     this.el.get_end_iter(out e);
1058                     var ret = this.el.get_text(s,e,true);
1059                     //print("TO STRING? " + ret);
1060                     return ret;
1061                 }
1062         }
1063
1064         public class Xcls_EventControllerKey11 : Object
1065         {
1066                 public Gtk.EventControllerKey el;
1067                 private Editor  _this;
1068
1069
1070                         // my vars (def)
1071
1072                 // ctor
1073                 public Xcls_EventControllerKey11(Editor _owner )
1074                 {
1075                         _this = _owner;
1076                         this.el = new Gtk.EventControllerKey();
1077
1078                         // my vars (dec)
1079
1080                         // set gobject values
1081
1082                         //listeners
1083                         this.el.key_released.connect( (keyval, keycode, state) => {
1084                         
1085                           
1086                             if (keyval == Gdk.Key.s && (state & Gdk.ModifierType.CONTROL_MASK ) > 0 ) {
1087                                 GLib.debug("SAVE: ctrl-S  pressed");
1088                                 _this.saveContents();
1089                                 return;
1090                             }
1091                             
1092                             if (keyval == Gdk.Key.g && (state & Gdk.ModifierType.CONTROL_MASK ) > 0 ) {
1093                                     GLib.debug("SAVE: ctrl-g  pressed");
1094                                         _this.forwardSearch(true);
1095                                     return;
1096                                 }
1097                                 if (keyval == Gdk.Key.f && (state & Gdk.ModifierType.CONTROL_MASK ) > 0 ) {
1098                                     GLib.debug("SAVE: ctrl-f  pressed");
1099                                         _this.search_entry.el.grab_focus();
1100                                         _this.search_entry.el.select_region(0,-1);
1101                                     return;
1102                                 }
1103                                 if (keyval == Gdk.Key.space && (state & Gdk.ModifierType.CONTROL_MASK ) > 0 ) {
1104                                         _this.view.el.show_completion();
1105                                 }
1106                                 
1107                                 Gtk.TextIter iter;
1108                                 _this.buffer.el.get_iter_at_offset( out iter, _this.buffer.el.cursor_position);  
1109                                 var line  = iter.get_line();
1110                                 var offset = iter.get_line_offset();
1111                                 GLib.debug("line  %d  off %d", line ,offset);
1112                                 if (_this.prop != null) {
1113                                         line += _this.prop.start_line + 1; // i think..
1114                                         offset += 12; // should probably be 8 without namespaced 
1115                                         GLib.debug("guess line  %d  off %d", line ,offset);
1116                                 } 
1117                             //_this.view.el.show_completion();
1118                            // print(event.key.keyval)
1119                            
1120                            
1121                            
1122                             
1123                             return;
1124                          
1125                          
1126                         });
1127                 }
1128
1129                 // user defined functions
1130         }
1131
1132
1133
1134         public class Xcls_Box12 : Object
1135         {
1136                 public Gtk.Box el;
1137                 private Editor  _this;
1138
1139
1140                         // my vars (def)
1141
1142                 // ctor
1143                 public Xcls_Box12(Editor _owner )
1144                 {
1145                         _this = _owner;
1146                         this.el = new Gtk.Box( Gtk.Orientation.HORIZONTAL, 0 );
1147
1148                         // my vars (dec)
1149
1150                         // set gobject values
1151                         this.el.homogeneous = false;
1152                         this.el.vexpand = false;
1153                         new Xcls_search_entry( _this );
1154                         this.el.append( _this.search_entry.el );
1155                         new Xcls_search_results( _this );
1156                         this.el.append( _this.search_results.el );
1157                         new Xcls_nextBtn( _this );
1158                         this.el.append( _this.nextBtn.el );
1159                         new Xcls_backBtn( _this );
1160                         this.el.append( _this.backBtn.el );
1161                         var child_5 = new Xcls_MenuButton18( _this );
1162                         child_5.ref();
1163                         this.el.append( child_5.el );
1164                 }
1165
1166                 // user defined functions
1167         }
1168         public class Xcls_search_entry : Object
1169         {
1170                 public Gtk.SearchEntry el;
1171                 private Editor  _this;
1172
1173
1174                         // my vars (def)
1175                 public Gtk.CssProvider css;
1176
1177                 // ctor
1178                 public Xcls_search_entry(Editor _owner )
1179                 {
1180                         _this = _owner;
1181                         _this.search_entry = this;
1182                         this.el = new Gtk.SearchEntry();
1183
1184                         // my vars (dec)
1185
1186                         // set gobject values
1187                         this.el.name = "editor-search-entry";
1188                         this.el.hexpand = true;
1189                         this.el.placeholder_text = "Press enter to search";
1190                         this.el.search_delay = 3;
1191                         var child_1 = new Xcls_EventControllerKey14( _this );
1192                         child_1.ref();
1193                         this.el.add_controller(  child_1.el );
1194
1195                         //listeners
1196                         this.el.search_changed.connect( ( ) => {
1197                         
1198                         _this.search(_this.search_entry.el.text);
1199                                  _this.search_results.updateResults();
1200                         
1201                                 GLib.Timeout.add_seconds(1,() => {
1202                                          _this.search_results.updateResults();
1203                                          return false;
1204                                  });
1205                         });
1206                 }
1207
1208                 // user defined functions
1209                 public void forwardSearch (bool change_focus) {
1210                 
1211                 
1212                         _this.forwardSearch(change_focus);
1213                 
1214                 /*
1215                 
1216                         switch(_this.windowstate.state) {
1217                                 case WindowState.State.CODEONLY:
1218                                 //case WindowState.State.CODE:
1219                                         // search the code being edited..
1220                                         _this.windowstate.code_editor_tab.forwardSearch(change_focus);
1221                                          
1222                                         break;
1223                                 case WindowState.State.PREVIEW:
1224                                         if (_this.windowstate.file.xtype == "Gtk") {
1225                                                 _this.windowstate.window_gladeview.forwardSearch(change_focus);
1226                                         } else { 
1227                                                  _this.windowstate.window_rooview.forwardSearch(change_focus);
1228                                         }
1229                                 
1230                                         break;
1231                         }
1232                         */
1233                         
1234                 }
1235         }
1236         public class Xcls_EventControllerKey14 : Object
1237         {
1238                 public Gtk.EventControllerKey el;
1239                 private Editor  _this;
1240
1241
1242                         // my vars (def)
1243
1244                 // ctor
1245                 public Xcls_EventControllerKey14(Editor _owner )
1246                 {
1247                         _this = _owner;
1248                         this.el = new Gtk.EventControllerKey();
1249
1250                         // my vars (dec)
1251
1252                         // set gobject values
1253
1254                         //listeners
1255                         this.el.key_pressed.connect( (keyval, keycode, state) => {
1256                         
1257                                 if (keyval == Gdk.Key.g && (state & Gdk.ModifierType.CONTROL_MASK ) > 0 ) {
1258                                     GLib.debug("SAVE: ctrl-g  pressed");
1259                                         _this.forwardSearch(true);
1260                                     return true;
1261                                 }
1262                             
1263                           
1264                                 if (keyval == Gdk.Key.Return && _this.search_entry.el.text.length > 0) {
1265                                         _this.forwardSearch(true);
1266                                         
1267                                         
1268                                     return true;
1269                         
1270                                 }    
1271                            // print(event.key.keyval)
1272                            
1273                             return false;
1274                         });
1275                 }
1276
1277                 // user defined functions
1278         }
1279
1280
1281         public class Xcls_search_results : Object
1282         {
1283                 public Gtk.Label el;
1284                 private Editor  _this;
1285
1286
1287                         // my vars (def)
1288
1289                 // ctor
1290                 public Xcls_search_results(Editor _owner )
1291                 {
1292                         _this = _owner;
1293                         _this.search_results = this;
1294                         this.el = new Gtk.Label( "No Results" );
1295
1296                         // my vars (dec)
1297
1298                         // set gobject values
1299                         this.el.margin_end = 4;
1300                         this.el.margin_start = 4;
1301                 }
1302
1303                 // user defined functions
1304                 public void updateResults () {
1305                         this.el.visible = true;
1306                         
1307                         var res = _this.searchcontext.get_occurrences_count();
1308                         if (res < 0) {
1309                                 _this.search_results.el.label = "??? Matches";          
1310                                 return;
1311                         }
1312                 
1313                         _this.nextBtn.el.sensitive = false;
1314                         _this.backBtn.el.sensitive = false;     
1315                 
1316                         if (res > 0) {
1317                                 _this.search_results.el.label = "%d Matches".printf(res);
1318                                 _this.nextBtn.el.sensitive = true;
1319                                 _this.backBtn.el.sensitive = true;
1320                                 return;
1321                         } 
1322                         _this.search_results.el.label = "No Matches";
1323                         
1324                 }
1325         }
1326
1327         public class Xcls_nextBtn : Object
1328         {
1329                 public Gtk.Button el;
1330                 private Editor  _this;
1331
1332
1333                         // my vars (def)
1334                 public bool always_show_image;
1335
1336                 // ctor
1337                 public Xcls_nextBtn(Editor _owner )
1338                 {
1339                         _this = _owner;
1340                         _this.nextBtn = this;
1341                         this.el = new Gtk.Button();
1342
1343                         // my vars (dec)
1344                         this.always_show_image = true;
1345
1346                         // set gobject values
1347                         this.el.icon_name = "go-down";
1348                         this.el.sensitive = false;
1349
1350                         //listeners
1351                         this.el.clicked.connect( (event) => {
1352                         
1353                                 _this.forwardSearch(true);
1354                                 
1355                                  
1356                         });
1357                 }
1358
1359                 // user defined functions
1360         }
1361
1362         public class Xcls_backBtn : Object
1363         {
1364                 public Gtk.Button el;
1365                 private Editor  _this;
1366
1367
1368                         // my vars (def)
1369                 public bool always_show_image;
1370
1371                 // ctor
1372                 public Xcls_backBtn(Editor _owner )
1373                 {
1374                         _this = _owner;
1375                         _this.backBtn = this;
1376                         this.el = new Gtk.Button();
1377
1378                         // my vars (dec)
1379                         this.always_show_image = true;
1380
1381                         // set gobject values
1382                         this.el.icon_name = "go-up";
1383                         this.el.sensitive = false;
1384
1385                         //listeners
1386                         this.el.clicked.connect( (event) => {
1387                         
1388                                 _this.backSearch(true);
1389                                  
1390                         });
1391                 }
1392
1393                 // user defined functions
1394         }
1395
1396         public class Xcls_MenuButton18 : Object
1397         {
1398                 public Gtk.MenuButton el;
1399                 private Editor  _this;
1400
1401
1402                         // my vars (def)
1403                 public bool always_show_image;
1404
1405                 // ctor
1406                 public Xcls_MenuButton18(Editor _owner )
1407                 {
1408                         _this = _owner;
1409                         this.el = new Gtk.MenuButton();
1410
1411                         // my vars (dec)
1412                         this.always_show_image = true;
1413
1414                         // set gobject values
1415                         this.el.icon_name = "emblem-system";
1416                         this.el.always_show_arrow = true;
1417                         new Xcls_search_settings( _this );
1418                         this.el.popover = _this.search_settings.el;
1419                 }
1420
1421                 // user defined functions
1422         }
1423         public class Xcls_search_settings : Object
1424         {
1425                 public Gtk.Popover el;
1426                 private Editor  _this;
1427
1428
1429                         // my vars (def)
1430
1431                 // ctor
1432                 public Xcls_search_settings(Editor _owner )
1433                 {
1434                         _this = _owner;
1435                         _this.search_settings = this;
1436                         this.el = new Gtk.Popover();
1437
1438                         // my vars (dec)
1439
1440                         // set gobject values
1441                         var child_1 = new Xcls_Box20( _this );
1442                         this.el.child = child_1.el;
1443                 }
1444
1445                 // user defined functions
1446         }
1447         public class Xcls_Box20 : Object
1448         {
1449                 public Gtk.Box el;
1450                 private Editor  _this;
1451
1452
1453                         // my vars (def)
1454
1455                 // ctor
1456                 public Xcls_Box20(Editor _owner )
1457                 {
1458                         _this = _owner;
1459                         this.el = new Gtk.Box( Gtk.Orientation.VERTICAL, 0 );
1460
1461                         // my vars (dec)
1462
1463                         // set gobject values
1464                         new Xcls_case_sensitive( _this );
1465                         this.el.append( _this.case_sensitive.el );
1466                         new Xcls_regex( _this );
1467                         this.el.append( _this.regex.el );
1468                         new Xcls_multiline( _this );
1469                         this.el.append( _this.multiline.el );
1470                 }
1471
1472                 // user defined functions
1473         }
1474         public class Xcls_case_sensitive : Object
1475         {
1476                 public Gtk.CheckButton el;
1477                 private Editor  _this;
1478
1479
1480                         // my vars (def)
1481
1482                 // ctor
1483                 public Xcls_case_sensitive(Editor _owner )
1484                 {
1485                         _this = _owner;
1486                         _this.case_sensitive = this;
1487                         this.el = new Gtk.CheckButton();
1488
1489                         // my vars (dec)
1490
1491                         // set gobject values
1492                         this.el.label = "Case Sensitive";
1493
1494                         // init method
1495
1496                         {
1497                                 this.el.show();
1498                         }
1499                 }
1500
1501                 // user defined functions
1502         }
1503
1504         public class Xcls_regex : Object
1505         {
1506                 public Gtk.CheckButton el;
1507                 private Editor  _this;
1508
1509
1510                         // my vars (def)
1511
1512                 // ctor
1513                 public Xcls_regex(Editor _owner )
1514                 {
1515                         _this = _owner;
1516                         _this.regex = this;
1517                         this.el = new Gtk.CheckButton();
1518
1519                         // my vars (dec)
1520
1521                         // set gobject values
1522                         this.el.label = "Regex";
1523
1524                         // init method
1525
1526                         {
1527                                 this.el.show();
1528                         }
1529                 }
1530
1531                 // user defined functions
1532         }
1533
1534         public class Xcls_multiline : Object
1535         {
1536                 public Gtk.CheckButton el;
1537                 private Editor  _this;
1538
1539
1540                         // my vars (def)
1541
1542                 // ctor
1543                 public Xcls_multiline(Editor _owner )
1544                 {
1545                         _this = _owner;
1546                         _this.multiline = this;
1547                         this.el = new Gtk.CheckButton();
1548
1549                         // my vars (dec)
1550
1551                         // set gobject values
1552                         this.el.label = "Multi-line (add \\n)";
1553                 }
1554
1555                 // user defined functions
1556         }
1557
1558
1559
1560
1561
1562 }