Fix #8049 - language server hover and editor hover (not supported for gtkview / rooview)
[roobuilder] / src / Builder4 / Editor.vala
index 845175e..74af01c 100644 (file)
@@ -17,6 +17,7 @@ public class Editor : Object
        public Xcls_RightEditor RightEditor;
        public Xcls_view view;
        public Xcls_buffer buffer;
+       public Xcls_keystate keystate;
        public Xcls_search_entry search_entry;
        public Xcls_search_results search_results;
        public Xcls_nextBtn nextBtn;
@@ -32,6 +33,7 @@ public class Editor : Object
        public bool dirty;
        public int pos_root_y;
        public bool pos;
+       public int last_error_counter;
        public GtkSource.SearchContext searchcontext;
        public int last_search_end;
        public signal void save ();
@@ -50,6 +52,7 @@ public class Editor : Object
                this.window = null;
                this.dirty = false;
                this.pos = false;
+               this.last_error_counter = 0;
                this.searchcontext = null;
                this.last_search_end = 0;
                this.file = null;
@@ -61,7 +64,7 @@ public class Editor : Object
                this.el.homogeneous = false;
                this.el.hexpand = true;
                this.el.vexpand = true;
-               var child_1 = new Xcls_Box2( _this );
+               var child_1 = new Xcls_Box1( _this );
                child_1.ref();
                this.el.append( child_1.el );
                new Xcls_RightEditor( _this );
@@ -143,13 +146,15 @@ public class Editor : Object
        
                // find the text for the node..
                this.view.load( prop.val );
-               
+               this.updateErrorMarks();
                
                this.close_btn.el.show();       
            
            } else {
                this.view.load(        file.toSource() );
+                this.updateErrorMarks();
                this.close_btn.el.hide();
+               
            }
         
        }
@@ -157,7 +162,7 @@ public class Editor : Object
        
                if (this.searchcontext == null) {
                        return;
-               } 
+               }
                
                Gtk.TextIter beg, st,en;
                bool has_wrapped_around;
@@ -240,7 +245,7 @@ public class Editor : Object
           
        
        }
-       public void updateErrorMarks (string category) {
+       public void updateErrorMarks () {
                
         
        
@@ -249,7 +254,8 @@ public class Editor : Object
                Gtk.TextIter end;     
                buf.get_bounds (out start, out end);
        
-               buf.remove_source_marks (start, end, category);
+               
+       
         
                //GLib.debug("highlight errors");                
        
@@ -270,52 +276,94 @@ public class Editor : Object
                        return;
        
                }
-               var ar = this.file.getErrors(category);
-               if (ar == null || ar.get_n_items() < 1) {
+               var ar = this.file.getErrors();
+               if (ar.size < 1) {
+                       buf.remove_source_marks (start, end, "ERR");
+                       buf.remove_source_marks (start, end, "WARN");
+                       buf.remove_source_marks (start, end, "DEPR");
+                       buf.remove_tag_by_name ("ERR", start, end);
+                       buf.remove_tag_by_name ("WARN", start, end);
+                       buf.remove_tag_by_name ("DEPR", start, end);
+                       this.last_error_counter = file.error_counter ;
                        //GLib.debug("highlight %s :  %s has no errors", this.file.relpath, category);
                        return;
                }
-        
+               
        
-        
+        // basicaly check if there is no change, then we do not do any update..
+        // we can do this by just using an error counter?
+        // if that's changed then we will do an update, otherwise dont bother.
+                 
                
                var offset = 0;
-                
+               var hoffset = 0;
        
                var tlines = buf.get_line_count () +1;
                
                if (_this.prop != null) {
                        // this still seems flaky...
-                       
+       
                        tlines = _this.prop.end_line;
                        offset = _this.prop.start_line;
+                       hoffset = _this.node.node_pad.length + 2; //shift it left  by 2 ? ..
+                       
                         
-               }
-                
-               for (var i = 0; i < ar.get_n_items();i++) {
-                       var err = (Palete.CompileError) ar.get_item(i);
+               } else {
+                       // no update...
+                       if (this.last_error_counter == file.error_counter) {
                        
+                               return;
+                       }
+               
+               }
+               buf.remove_source_marks (start, end, "ERR");
+               buf.remove_source_marks (start, end, "WARN");
+               buf.remove_source_marks (start, end, "DEPR");
+               buf.remove_tag_by_name ("ERR", start, end);
+               buf.remove_tag_by_name ("WARN", start, end);
+               buf.remove_tag_by_name ("DEPR", start, end);
+               
+               foreach(var diag in ar) { 
                     Gtk.TextIter iter;
        //        print("get inter\n");
-                   var eline = err.line - offset;
+                   var eline = (int)diag.range.start.line - offset;
+                   var eline_to = (int)diag.range.end.line - offset;
+                   //var eline =  diag.range.end_line - offset;
                    //GLib.debug("GOT ERROR on line %d -- converted to %d  (offset = %d)",
                    //  err.line ,eline, offset);
                    
                    
                    if (eline > tlines || eline < 0) {
-                       return;
+                       continue;
                    }
-                  
                    
                    buf.get_iter_at_line( out iter, eline);
-                  
-                  
-                       var msg = "Line: %d %s : %s".printf(eline+1, err.category, err.msg);
-                   buf.create_source_mark( msg, err.category, iter);
+                       var msg = "Line: %d %s : %s".printf(eline+1, diag.category, diag.message);
+                   buf.create_source_mark( msg, diag.category, iter);
+                   
+                   var spos = (int)diag.range.start.character - hoffset;
+                   if (spos < 0) { spos =0 ; }
+                   if (spos > iter.get_chars_in_line()) {
+                       spos = iter.get_chars_in_line();
+               }
+                       buf.get_iter_at_line( out iter, eline_to);
+                       var epos = (int)diag.range.end.character - hoffset;
+                   if (epos < 0) { epos =0 ; }
+                   if (epos > iter.get_chars_in_line()) {
+                       epos = iter.get_chars_in_line();
+               }
+                    
+                   
+                   buf.get_iter_at_line_offset( out start, eline, spos); 
+                  
+                   buf.get_iter_at_line_offset( out end, eline_to,epos); 
+                       
+                   buf.apply_tag_by_name(diag.category, start, end);
+                   
                   // GLib.debug("set line %d to %s", eline, msg);
                    //this.marks.set(eline, msg);
                }
-               return ;
+               this.last_error_counter = file.error_counter ;
        
        
        
@@ -337,7 +385,7 @@ public class Editor : Object
                        return false;
                });   
        }
-       public class Xcls_Box2 : Object
+       public class Xcls_Box1 : Object
        {
                public Gtk.Box el;
                private Editor  _this;
@@ -346,7 +394,7 @@ public class Editor : Object
                        // my vars (def)
 
                // ctor
-               public Xcls_Box2(Editor _owner )
+               public Xcls_Box1(Editor _owner )
                {
                        _this = _owner;
                        this.el = new Gtk.Box( Gtk.Orientation.HORIZONTAL, 0 );
@@ -358,10 +406,10 @@ public class Editor : Object
                        this.el.hexpand = true;
                        new Xcls_save_button( _this );
                        this.el.append( _this.save_button.el );
-                       var child_2 = new Xcls_Label4( _this );
+                       var child_2 = new Xcls_Label3( _this );
                        child_2.ref();
                        this.el.append( child_2.el );
-                       var child_3 = new Xcls_Scale5( _this );
+                       var child_3 = new Xcls_Scale4( _this );
                        child_3.ref();
                        this.el.append( child_3.el );
                        new Xcls_close_btn( _this );
@@ -399,7 +447,7 @@ public class Editor : Object
                // user defined functions
        }
 
-       public class Xcls_Label4 : Object
+       public class Xcls_Label3 : Object
        {
                public Gtk.Label el;
                private Editor  _this;
@@ -408,7 +456,7 @@ public class Editor : Object
                        // my vars (def)
 
                // ctor
-               public Xcls_Label4(Editor _owner )
+               public Xcls_Label3(Editor _owner )
                {
                        _this = _owner;
                        this.el = new Gtk.Label( null );
@@ -422,7 +470,7 @@ public class Editor : Object
                // user defined functions
        }
 
-       public class Xcls_Scale5 : Object
+       public class Xcls_Scale4 : Object
        {
                public Gtk.Scale el;
                private Editor  _this;
@@ -431,7 +479,7 @@ public class Editor : Object
                        // my vars (def)
 
                // ctor
-               public Xcls_Scale5(Editor _owner )
+               public Xcls_Scale4(Editor _owner )
                {
                        _this = _owner;
                        this.el = new Gtk.Scale.with_range (Gtk.Orientation.HORIZONTAL,6, 30, 1);
@@ -448,18 +496,26 @@ public class Editor : Object
                        // init method
 
                        {
-                               this.el.set_range(6,30);
-                               this.el.set_value(8);
+                               //this.el.set_range(6,30);
+                               this.el.set_value ( BuilderApplication.settings.editor_font_size);
+                               BuilderApplication.settings.editor_font_size_updated.connect(
+                                       () => {
+                                               BuilderApplication.settings.editor_font_size_inchange = true;
+                                       //      GLib.debug("update range");
+                                               this.el.set_value (BuilderApplication.settings.editor_font_size);
+                                               BuilderApplication.settings.editor_font_size_inchange = false;
+                                       }
+                               );
+                               
+                        
                        }
 
                        //listeners
                        this.el.change_value.connect( (st, val ) => {
-                                
-                                  
-                                 _this.view.css.load_from_string(
-                                               "#editor-view { font: %dpx monospace; }".printf((int)val)
-                                  );
-                            
+                               if (BuilderApplication.settings.editor_font_size_inchange) {
+                                       return false;
+                               }
+                               BuilderApplication.settings.editor_font_size = val;
                                return false;
                        });
                }
@@ -486,7 +542,8 @@ public class Editor : Object
 
                        // set gobject values
                        this.el.icon_name = "window-close";
-                       var child_1 = new Xcls_Image7( _this );
+                       var child_1 = new Xcls_Image6( _this );
+                       child_1.ref();
                        this.el.child = child_1.el;
 
                        //listeners
@@ -498,7 +555,7 @@ public class Editor : Object
 
                // user defined functions
        }
-       public class Xcls_Image7 : Object
+       public class Xcls_Image6 : Object
        {
                public Gtk.Image el;
                private Editor  _this;
@@ -507,7 +564,7 @@ public class Editor : Object
                        // my vars (def)
 
                // ctor
-               public Xcls_Image7(Editor _owner )
+               public Xcls_Image6(Editor _owner )
                {
                        _this = _owner;
                        this.el = new Gtk.Image();
@@ -581,52 +638,33 @@ public class Editor : Object
                        this.el.hexpand = true;
                        this.el.vexpand = true;
                        this.el.has_tooltip = true;
+                       this.el.css_classes = { "code-editor" };
                        this.el.tab_width = 4;
                        this.el.highlight_current_line = true;
                        new Xcls_buffer( _this );
                        this.el.buffer = _this.buffer.el;
-                       var child_2 = new Xcls_EventControllerKey11( _this );
-                       child_2.ref();
-                       this.el.add_controller(  child_2.el );
+                       new Xcls_keystate( _this );
+                       this.el.add_controller(  _this.keystate.el );
+                       var child_3 = new Xcls_EventControllerScroll11( _this );
+                       child_3.ref();
+                       this.el.add_controller(  child_3.el );
 
                        // init method
 
-                       this.css = new Gtk.CssProvider();
-                       
-                       this.css.load_from_string(
-                               "#editor-view { font:  12px monospace;}"
-                       );
-                        
-                       Gtk.StyleContext.add_provider_for_display(
-                               this.el.get_display(),
-                               this.css,
-                               Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
+                       this.el.completion.add_provider(
+                               new Palete.CompletionProvider(_this)
                        );
-                               
                         
-                                
-                       /*
-                       this is pretty flakey - triggers Gtk with  < 0 d
-                        var cp = new GtkSource.CompletionWords("test"); 
-                        cp.minimum_word_size  = 3;
-                        //cp.priority = 100; //?? does this do anything
-                        cp.proposals_batch_size  = 10;
-                        cp.scan_batch_size = 1000;
-                        
-                       cp.register(_this.buffer.el);
-                       this.el.completion.add_provider(cp);
-                       */
-                       this.el.completion.add_provider(new Palete.CompletionProvider(_this));
-                         
+                       var hover = this.el.get_hover();
+                       hover.add_provider(new Palete.HoverProvider(_this));
+                       
                        //this.el.completion.unblock_interactive();
                        this.el.completion.select_on_show = true; // select
                        //this.el.completion.remember_info_visibility    = true;
                        
                        
                        var attrs = new GtkSource.MarkAttributes();
-                       var  pink =   Gdk.RGBA();
-                       pink.parse ( "pink");
-                       attrs.set_background ( pink);
+                       
                        attrs.set_icon_name ( "process-stop");    
                        attrs.query_tooltip_text.connect(( mark) => {
                             GLib.debug("tooltip query? %s", mark.name);
@@ -638,10 +676,9 @@ public class Editor : Object
                        });
                        this.el.set_mark_attributes ("ERR", attrs, 1);
                        attrs.ref();
-                        var wattrs = new GtkSource.MarkAttributes();
-                       var  blue =   Gdk.RGBA();
-                       blue.parse ( "#ABF4EB");
-                       wattrs.set_background ( blue);
+                       
+                       
+                       var wattrs = new GtkSource.MarkAttributes();
                        wattrs.set_icon_name ( "process-stop");    
                        wattrs.query_tooltip_text.connect(( mark) => {
                             GLib.debug("tooltip query? %s", mark.name);
@@ -654,20 +691,19 @@ public class Editor : Object
                        this.el.set_mark_attributes ("WARN", wattrs, 1);
                        wattrs.ref();
                        
+                        
+                       var dattrs = new GtkSource.MarkAttributes();
+                        
+                       dattrs.set_icon_name ( "process-stop"); 
                        
-                        var dattrs = new GtkSource.MarkAttributes();
-                       var  purple =   Gdk.RGBA();
-                       purple.parse ( "#EEA9FF");
-                       dattrs.set_background ( purple);
-                       dattrs.set_icon_name ( "process-stop");    
                        dattrs.query_tooltip_text.connect(( mark) => {
                                GLib.debug("tooltip query? %s", mark.name);
                            return strdup(mark.name);
                        });
-                       dattrs.query_tooltip_markup.connect(( mark) => {
-                               GLib.debug("tooltip query? %s", mark.name);
-                           return strdup(mark.name);
-                       });
+                       //dattrs.query_tooltip_markup.connect(( mark) => {
+                       //      GLib.debug("tooltip query? %s", mark.name);
+                        //   return strdup(mark.name);
+                       //});
                        this.el.set_mark_attributes ("DEPR", dattrs, 1);
                        dattrs.ref();    
                        
@@ -776,6 +812,7 @@ public class Editor : Object
                    _this.dirty = false;
                    this.el.grab_focus();
                    _this.save_button.el.sensitive = false;
+                   _this.last_error_counter = -1;
                }
        }
        public class Xcls_buffer : Object
@@ -808,18 +845,20 @@ public class Editor : Object
 
                        // init method
 
-                       {
-                               var buf = this.el;
-                               buf.create_tag ("bold", "weight", Pango.Weight.BOLD);
-                           buf.create_tag ("type", "weight", Pango.Weight.BOLD, "foreground", "#204a87");
-                           buf.create_tag ("keyword", "weight", Pango.Weight.BOLD, "foreground", "#a40000");
-                           buf.create_tag ("text", "weight", Pango.Weight.NORMAL, "foreground", "#729fcf");
-                           buf.create_tag ("number", "weight", Pango.Weight.BOLD, "foreground", "#ad7fa8");
-                           buf.create_tag ("method", "weight", Pango.Weight.BOLD, "foreground", "#729fcf");
-                           buf.create_tag ("property", "weight", Pango.Weight.BOLD, "foreground", "#BC1F51");
-                           buf.create_tag ("variable", "weight", Pango.Weight.BOLD, "foreground", "#A518B5");
+                       var buf = this.el;
+                       buf.create_tag ("bold", "weight", Pango.Weight.BOLD);
+                       buf.create_tag ("type", "weight", Pango.Weight.BOLD, "foreground", "#204a87");
+                       buf.create_tag ("keyword", "weight", Pango.Weight.BOLD, "foreground", "#a40000");
+                       buf.create_tag ("text", "weight", Pango.Weight.NORMAL, "foreground", "#729fcf");
+                       buf.create_tag ("number", "weight", Pango.Weight.BOLD, "foreground", "#ad7fa8");
+                       buf.create_tag ("method", "weight", Pango.Weight.BOLD, "foreground", "#729fcf");
+                       buf.create_tag ("property", "weight", Pango.Weight.BOLD, "foreground", "#BC1F51");
+                       buf.create_tag ("variable", "weight", Pango.Weight.BOLD, "foreground", "#A518B5");
                        
-                       }
+                       
+                       buf.create_tag ("ERR", "weight", Pango.Weight.BOLD, "background", "pink");
+                       buf.create_tag ("WARN", "weight", Pango.Weight.BOLD, "background", "#ABF4EB");
+                       buf.create_tag ("DEPR", "weight", Pango.Weight.BOLD, "background", "#EEA9FF");
 
                        //listeners
                        this.el.changed.connect( () => {
@@ -837,63 +876,7 @@ public class Editor : Object
                }
 
                // user defined functions
-               public bool checkSyntax () {
-                
-                   
-                   var str = this.toString();
-                   
-                   // needed???
-                   if (this.error_line > 0) {
-                        Gtk.TextIter start;
-                        Gtk.TextIter end;     
-                       this.el.get_bounds (out start, out end);
-               
-                       this.el.remove_source_marks (start, end, null);
-                   }
-                   if (str.length < 1) {
-                       print("checkSyntax - empty string?\n");
-                       return true;
-                   }
-                   
-                   // bit presumptiona
-                   if (_this.file.xtype == "PlainFile") {
-                   
-                       // assume it's gtk...
-                        var  oldcode =_this.file.toSource();
-                       _this.file.setSource(str);
-                       _this.file.getLanguageServer().document_change(_this.file);
-                           BuilderApplication.showSpinner("appointment soon","document change pending");
-                       _this.file.setSource(oldcode);
-                       
-                                
-                       return true;
-                   
-                   }
-                  if (_this.file == null) {
-                      return true;
-                  }
-                
-                   
-               
-                     
-                    
-                   GLib.debug("calling validate");    
-                   // clear the buttons.
-                       if (_this.prop.name == "xns" || _this.prop.name == "xtype") {
-                               return true ;
-                       }
-                       var oldcode  = _this.prop.val;
-                       
-                       _this.prop.val = str;
-                   _this.file.getLanguageServer().document_change(_this.file);
-                   _this.prop.val = oldcode;
-                   
-                   
-                   //print("done mark line\n");
-                    
-                   return true; // at present allow saving - even if it's invalid..
-               }
-               public bool highlightErrorsJson (string type, Json.Object obj) {
+               public bool OLDhighlightErrorsJson (string type, Json.Object obj) {
                        Gtk.TextIter start;
                        Gtk.TextIter end;     
                        this.el.get_bounds (out start, out end);
@@ -1004,6 +987,65 @@ public class Editor : Object
                
                
                        }
+               public bool checkSyntax () {
+                
+                   
+                   var str = this.toString();
+                   
+                   // needed???
+                   if (this.error_line > 0) {
+                        Gtk.TextIter start;
+                        Gtk.TextIter end;     
+                       this.el.get_bounds (out start, out end);
+               
+                       this.el.remove_source_marks (start, end, null);
+                   }
+                   if (str.length < 1) {
+                       print("checkSyntax - empty string?\n");
+                       return true;
+                   }
+                   
+                   // bit presumptiona
+                   if (_this.file.xtype == "PlainFile") {
+                   
+                       // assume it's gtk...
+                        var  oldcode =_this.file.toSource();
+                       _this.file.setSource(str);
+                           BuilderApplication.showSpinner("appointment soon","document change pending");
+                       _this.file.getLanguageServer().document_change(_this.file);
+               
+                       _this.file.setSource(oldcode);
+                       
+                                
+                       return true;
+                   
+                   }
+                  if (_this.file == null) {
+                      return true;
+                  }
+                
+                   
+               
+                     
+                    
+                   GLib.debug("calling validate");    
+                   // clear the buttons.
+                       if (_this.prop.name == "xns" || _this.prop.name == "xtype") {
+                               return true ;
+                       }
+                       var oldcode  = _this.prop.val;
+                       
+                       _this.prop.val = str;
+                       _this.node.updated_count++;
+                   _this.file.getLanguageServer().document_change(_this.file);
+                   _this.node.updated_count++;
+                   _this.prop.val = oldcode;
+                   
+                   
+                   //print("done mark line\n");
+                    
+                   return true; // at present allow saving - even if it's invalid..
+               }
                public bool highlightErrors ( Gee.HashMap<int,string> validate_res) {
                         
                        this.error_line = validate_res.size;
@@ -1039,28 +1081,33 @@ public class Editor : Object
                }
        }
 
-       public class Xcls_EventControllerKey11 : Object
+       public class Xcls_keystate : Object
        {
                public Gtk.EventControllerKey el;
                private Editor  _this;
 
 
                        // my vars (def)
+               public bool is_control;
 
                // ctor
-               public Xcls_EventControllerKey11(Editor _owner )
+               public Xcls_keystate(Editor _owner )
                {
                        _this = _owner;
+                       _this.keystate = this;
                        this.el = new Gtk.EventControllerKey();
 
                        // my vars (dec)
+                       this.is_control = false;
 
                        // set gobject values
 
                        //listeners
                        this.el.key_released.connect( (keyval, keycode, state) => {
                        
-                         
+                                if (keyval == Gdk.Key.Control_L || keyval == Gdk.Key.Control_R) {
+                                       this.is_control = false;
+                               }
                            if (keyval == Gdk.Key.s && (state & Gdk.ModifierType.CONTROL_MASK ) > 0 ) {
                                GLib.debug("SAVE: ctrl-S  pressed");
                                _this.saveContents();
@@ -1102,6 +1149,61 @@ public class Editor : Object
                         
                         
                        });
+                       this.el.key_pressed.connect( (keyval, keycode, state) => {
+                       
+                               if (keyval == Gdk.Key.Control_L || keyval == Gdk.Key.Control_R) {
+                                       this.is_control = true;
+                               }
+                               return false;
+                       });
+               }
+
+               // user defined functions
+       }
+
+       public class Xcls_EventControllerScroll11 : Object
+       {
+               public Gtk.EventControllerScroll el;
+               private Editor  _this;
+
+
+                       // my vars (def)
+               public double distance;
+
+               // ctor
+               public Xcls_EventControllerScroll11(Editor _owner )
+               {
+                       _this = _owner;
+                       this.el = new Gtk.EventControllerScroll( Gtk.EventControllerScrollFlags.VERTICAL );
+
+                       // my vars (dec)
+                       this.distance = 0.0f;
+
+                       // set gobject values
+
+                       //listeners
+                       this.el.scroll.connect( (dx, dy) => {
+                               if (!_this.keystate.is_control) {
+                                       return false;
+                               }
+                                //GLib.debug("scroll %f",  dy);
+                               
+                               this.distance += dy;
+                               
+                               //GLib.debug("scroll %f / %f",  dy, this.distance);
+                        
+                                if (this.distance < -1) {
+                        
+                                       BuilderApplication.settings.editor_font_size ++;
+                                       this.distance = 0;
+                               }
+                               if (this.distance > 1) {
+                                       BuilderApplication.settings.editor_font_size --;
+                                       this.distance = 0;
+                               }
+                                
+                               return true;
+                       });
                }
 
                // user defined functions
@@ -1417,6 +1519,7 @@ public class Editor : Object
 
                        // set gobject values
                        var child_1 = new Xcls_Box20( _this );
+                       child_1.ref();
                        this.el.child = child_1.el;
                }