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