Fix #8104 - update nav tree by comparing changes
[roobuilder] / src / Lsp.vala
index b5c4f00..21ab644 100644 (file)
@@ -62,6 +62,12 @@ namespace Lsp {
     }
 
     public  class Position : Object, Gee.Comparable<Position> {
+        
+        public Position(uint line, uint chr)
+        {
+               this.line = line;
+               this.character = chr;
+        }
         /**
          * Line position in a document (zero-based).
          */
@@ -78,12 +84,16 @@ namespace Lsp {
         public uint character { get; set; default = -1; }
 
         public int compare_to (Position other) {
+             
             return line > other.line ? 1 :
                 (line == other.line ?
                  (character > other.character ? 1 :
                   (character == other.character ? 0 : -1)) : -1);
         }
-
+        public bool equals(Position o) {
+               return o.line == this.line && o.character == this.character;
+       }
+               
         public string to_string () {
             return @"$line:$character";
         }
@@ -98,14 +108,18 @@ namespace Lsp {
         }
 
         public Position translate (int dl = 0, int dc = 0) {
-            return new Position () {
-                line = this.line + dl,
-                character = this.character + dc
-            };
+            return new Position (this.character + dc, this.character + dc) ;
         }
     }
 
     public class Range : Object, Gee.Hashable<Range>, Gee.Comparable<Range> {
+        
+        public Range.simple(uint line, uint pos) {
+               var p =  new Position (line,pos);
+               this.start = p;
+               this.end = p;
+               
+        }
         /**
          * The range's start position.
          */
@@ -137,6 +151,11 @@ namespace Lsp {
         }
 
         public bool equal_to (Range other) { return this.to_string () == other.to_string (); }
+               public bool equals (Range o) {
+                       return this.filename == o.filename && 
+                                       this.start.equals(o.start) && 
+                                       this.end.equals(o.end);
+               }
 
         public int compare_to (Range other) {
             return start.compare_to (other.start);
@@ -156,11 +175,25 @@ namespace Lsp {
         }
 
         public bool contains (Position pos) {
-            return start.compare_to (pos) <= 0 && pos.compare_to (end) <= 0;
+               
+            var ret =  start.compare_to (pos) <= 0 && pos.compare_to (end) <= 0;
+           // GLib.debug( "range contains %d  (%d-%d) %s", (int)pos.line, (int)start.line, (int)end.line, ret ? "Y" : "N");
+            return ret;
         }
+       
     }
 
     public class Diagnostic : Object {
+        
+        public Diagnostic.simple ( int line, int character, string message)
+        {
+               this.message = message;
+               this.severity = DiagnosticSeverity.Error;
+               this.range =  new Range.simple(line, character );
+               
+               
+        
+        }
         /**
          * The range at which the message applies.
          */
@@ -204,6 +237,18 @@ namespace Lsp {
                private set {}
                
         }
+        public bool equals(Lsp.Diagnostic o) {
+                       var ret = this.range.equals(o.range) && this.severity == o.severity && this.message == o.message;
+               //GLib.debug("compare %s  (%s == %s)", ret ? "YES" : "NO", this.to_string(), o.to_string()); 
+               
+               
+               return ret;
+        }
+        public string to_string()
+        {
+               return "%s : %d - %s".printf(this.category, (int) this.range.start.line , this.message);
+        }
+        
     }
 
     /**
@@ -296,25 +341,18 @@ namespace Lsp {
     }
 
     public class DocumentSymbol : Object, Json.Serializable {
-        private Vala.SourceReference? _source_reference;
-        public string name { get; set; }
-        public string? detail { get; set; }
-        public SymbolKind kind { get; set; }
-        public bool deprecated { get; set; }
-        private Range? _initial_range;
-        public Range range {
-            owned get {
-                if (_initial_range == null)
-                    _initial_range = new Range.from_sourceref (children.first ()._source_reference);
-                
-                return children.fold<Range> ((child, current_range) => current_range.union (child.range), _initial_range);
-            }
-        }
-        public Range selectionRange { get; set; }
-        public Gee.List<DocumentSymbol> children { get; private set; default = new Gee.LinkedList<DocumentSymbol> (); }
-        public string? parent_name;
 
-        private DocumentSymbol () {}
+               public string name { get; set; }
+               public string detail { get; set; default = ""; }
+               public SymbolKind kind { get; set; }
+               public bool deprecated { get; set; }
+
+               public Range range { get; set; } 
+               public Range selectionRange { get; set; }
+               public GLib.ListStore children { get;  set; default = new GLib.ListStore(typeof(DocumentSymbol)); }
+               public string? parent_name;
+
+               private DocumentSymbol () {}
 
         /**
          * @param type the data type containing this symbol, if there was one (not available for Namespaces, for example)
@@ -330,7 +368,7 @@ namespace Lsp {
                 // debug ("subroutine %s found (body @ %s)", sym.get_full_name (),
                 //         body_sref != null ? body_sref.to_string () : null);
                 if (body_sref != null && (body_sref.begin.line < body_sref.end.line ||
-                                          body_sref.begin.line == body_sref.end.line && body_sref.begin.pos <= body_sref.end.pos)) {
+                                val = GLib.Value (typeof(Gee.ArrayList));                          body_sref.begin.line == body_sref.end.line && body_sref.begin.pos <= body_sref.end.pos)) {
                     this._initial_range = this._initial_range.union (new Range.from_sourceref (body_sref));
                 }
             }
@@ -356,19 +394,133 @@ namespace Lsp {
         }
 
         public Json.Node serialize_property (string property_name, Value value, ParamSpec pspec) {
-            if (property_name != "children")
+           // if (property_name != "children")
                 return default_serialize_property (property_name, value, pspec);
-            var node = new Json.Node (Json.NodeType.ARRAY);
+            /*var node = new Json.Node (Json.NodeType.ARRAY);
             node.init_array (new Json.Array ());
             var array = node.get_array ();
             foreach (var child in children)
                 array.add_element (Json.gobject_serialize (child));
             return node;
+            */
         }
 
-        public bool deserialize_property (string property_name, out Value value, ParamSpec pspec, Json.Node property_node) {
-            error ("deserialization not supported");
-        }
+        public bool deserialize_property (string property_name, out Value value, ParamSpec pspec, Json.Node property_node) 
+           {
+               //GLib.debug("deserialise property %s" , property_name);
+               if (property_name != "children") {
+                   return default_deserialize_property (property_name, out value, pspec, property_node);
+               }
+            value = GLib.Value (typeof(GLib.ListStore));
+               if (property_node.get_node_type () != Json.NodeType.ARRAY) {
+                  // GLib.debug ("unexpected property node type for 'arguments' %s", property_node.get_node_type ().to_string ());
+                   return false;
+               }
+                       //GLib.debug("got child length of %d", (int) property_node.get_array ().get_length());
+               var arguments = new GLib.ListStore(typeof(DocumentSymbol));
+
+               property_node.get_array ().foreach_element ((array, index, element) => {
+                   
+                       var add= Json.gobject_deserialize ( typeof (DocumentSymbol),  array.get_element(index)) as DocumentSymbol;
+                               arguments.append( add);
+
+                  
+               });
+
+               value.set_object (arguments);
+               return true;
+          }
+          public string symbol_icon { 
+                       
+                       owned get {
+                               return this.kind.icon(); 
+                       }
+               }
+                
+               public string tooltip {
+                       owned get {
+                               //GLib.debug("%s : %s", this.name, this.detail);
+                               //var detail = this.detail == "" ? (this.kind.to_string() + ": " + this.name) : this.detail;
+                                return GLib.Markup.escape_text(this.detail + "\nline: " + this.range.start.line.to_string());
+                               
+                       }
+               }
+               public string sort_key {
+                       owned get { 
+                               return this.kind.sort_key().to_string() + "=" + this.name;
+                       }
+               }
+               
+               public DocumentSymbol? containsLine(uint line, uint chr)
+               {
+                       if (!this.range.contains(new Position(line, chr))) {
+                               return null;
+                       }
+
+                       for(var i = 0; i < this.children.get_n_items();i++) {
+                               var el = (DocumentSymbol)this.children.get_item(i);
+                               var ret = el.containsLine(line,chr);
+                               if (ret != null) {
+                                       return ret;
+                               }
+                       }
+                       return this;
+                       
+               }
+               // does not compare children...
+               public bool equals(DocumentSymbol sym) {
+                       return this.name == sym.name && 
+                                       this.kind == sym.kind && 
+                                       this.detail == sym.detail &&
+                                       sym.range.equals(this.range);
+               }
+               
+               public static void copyList(GLib.ListStore source, GLib.ListStore target) 
+               {
+                       //GLib.debug("copyList source=%d target=%d", (int)source.get_n_items(), (int)target.get_n_items());
+                       var i = 0;
+                       while (i < source.get_n_items()) {
+                               //GLib.debug("copyList compare %d", i);
+                               if (i >= target.get_n_items()) {
+                                       //GLib.debug("copyList append");
+                                       target.append(source.get_item(i));
+                                       i++;
+                                       continue;
+                               }
+                               var sel = (Lsp.DocumentSymbol) source.get_item(i);
+                               var tel = (Lsp.DocumentSymbol) target.get_item(i);
+                               if (!sel.equals(tel)) {
+                                       //GLib.debug("copyList replace");
+                                       target.remove(i);
+                                       target.insert(i, sel);
+                                       i++;
+                                       continue;
+                               }
+
+                               if (sel.children.get_n_items() < 1 && tel.children.get_n_items() < 1) {
+                                       i++;
+                                       //GLib.debug("copyList same  noChlidren %s", sel.name);
+                                       continue;
+
+                               }
+                               //GLib.debug("copyList same = updateChildren %s", sel.name);
+                               //
+                                       // they are the same (ignoring children
+                               copyList(sel.children,tel.children);
+                               i++;
+                       
+                       }
+                       // remove target items, that dont exist anymore
+                       while (i < target.get_n_items()) {
+                               //GLib.debug("copyList remove");
+                               target.remove(i);
+                       }
+                       
+                       
+               
+               }
+          
+          
     }
 
     public class SymbolInformation : Object {
@@ -380,7 +532,7 @@ namespace Lsp {
         public SymbolInformation.from_document_symbol (DocumentSymbol dsym, string uri) {
             this.name = dsym.name;
             this.kind = dsym.kind;
-            this.location = new Location (uri, dsym.range);
+          //  this.location = new Location (uri, dsym.range);
             this.containerName = dsym.parent_name;
         }
     }
@@ -412,7 +564,63 @@ namespace Lsp {
         Struct = 23,
         Event = 24,
         Operator = 25,
-        TypeParameter = 26
+        TypeParameter = 26;
+        
+        public string icon () { 
+                               
+                       switch (this) {
+                               
+                               // case         SymbolKind.Text: return "completion-snippet-symbolic";
+                               case    SymbolKind.Method: return "lang-method-symbolic";
+                               case    SymbolKind.Function: return "lang-function-symbolic";
+                               case    SymbolKind.Constructor: return "lang-method-symbolic";
+                               case    SymbolKind.Field: return "lang-struct-field-symbolic";
+                               case    SymbolKind.Variable: return "lang-variable-symbolic";
+                               case    SymbolKind.Class: return "lang-class-symbolic";
+                               case    SymbolKind.Interface: return "lang-class-symbolic";
+                               case    SymbolKind.Module: return "lang-namespace-symbolic";
+                               case    SymbolKind.Property:return "lang-struct-field-symbolic";
+                               //case  SymbolKind.Unit: return "lang-variable-symbolic";
+                               //case  SymbolKind.Value: return "lang-variable-symbolic";
+                               case    SymbolKind.Enum: return "lang-enum-symbolic";
+                               //case  SymbolKind.Keyword: return "completion-word-symbolic";
+                               //case  SymbolKind.Snippet: return "completion-snippet-symbolic";
+
+                               //case  SymbolKind.Color: return "lang-typedef-symbolic";
+                               case    SymbolKind.File:return "lang-typedef-symbolic";
+                               //case  SymbolKind.Reference: return "lang-typedef-symbolic";
+                               //case  SymbolKind.Folder:return "lang-typedef-symbolic";
+                               case    SymbolKind.EnumMember: return "lang-typedef-symbolic";
+                               case    SymbolKind.Constant:return "lang-typedef-symbolic";
+                               case    SymbolKind.Struct: return "lang-struct-symbolic";
+                               case    SymbolKind.Event:return "lang-typedef-symbolic";
+                               case    SymbolKind.Operator:return "lang-typedef-symbolic";
+                               case    SymbolKind.TypeParameter:return "lang-typedef-symbolic";
+                       
+                               default: 
+                                return "completion-snippet-symbolic";
+                                               
+                       }
+               }
+               public int sort_key() { 
+                        
+                       switch (this) {
+                               case Enum : return 1;
+                               case Class: return 2;
+                               
+                               case Constructor : return 1;
+                               case Method : return 2;
+                               case Field : return 3;
+                               case Property : return 3;
+                               
+                               default:
+                                       return 5;
+                       }       
+               
+               
+               
+               }
+        
     }
 
        public class CompletionList : Object, Json.Serializable {
@@ -635,6 +843,7 @@ namespace Lsp {
                if (property_name != "tags") {
                 return default_deserialize_property (property_name, out value, pspec, property_node);
             }
+            value = GLib.Value (typeof(Gee.ArrayList));
             if (property_node.get_node_type () != Json.NodeType.ARRAY) {
                 warning ("unexpected property node type for 'arguments' %s", property_node.get_node_type ().to_string ());
                 return false;
@@ -650,7 +859,7 @@ namespace Lsp {
                 }
             });
 
-            value.set_boxed (arguments);
+            value.set_object (arguments);
             return true;
        }
     }
@@ -807,6 +1016,12 @@ namespace Lsp {
     }
 
    public  class MarkedString : Object {
+               public MarkedString(string language, string value) 
+               {
+                       this.language = language;
+                       this.value = value;
+                       GLib.debug("new marked string %s : %s", language, value);
+               }
         public string language { get; set; }
         public string value { get; set; }
     }
@@ -844,8 +1059,30 @@ namespace Lsp {
             return node;
         }
 
-        public bool deserialize_property (string property_name, out Value value, ParamSpec pspec, Json.Node property_node) {
-            error ("deserialization not supported");
+        public bool deserialize_property (string property_name, out Value value, ParamSpec pspec, Json.Node property_node) 
+        {
+            if (property_name == "contents") {
+                value = GLib.Value (typeof(Gee.ArrayList));
+                       if (property_node.get_node_type () != Json.NodeType.ARRAY) {
+                           warning ("unexpected property node type for 'arguments' %s", property_node.get_node_type ().to_string ());
+                           return false;
+                       }
+                               var contents = new Gee.ArrayList<MarkedString>();
+
+                       property_node.get_array ().foreach_element ((array, index, element) => {
+                               var add = new MarkedString(
+                                               array.get_object_element(index).get_string_member("language"),
+                                               array.get_object_element(index).get_string_member("value")
+                                       );
+                    
+                       contents.add ( add );
+                    
+                       });
+                value.set_object (contents);
+                       return true;
+            } 
+            
+            return default_deserialize_property (property_name, out value, pspec, property_node);
         }
     }
 
@@ -937,9 +1174,10 @@ namespace Lsp {
             return node;
         }
 
-        public bool deserialize_property (string property_name, out GLib.Value value, GLib.ParamSpec pspec, Json.Node property_node) {
+        public bool deserialize_property (string property_name, out GLib.Value value, GLib.ParamSpec pspec, Json.Node property_node) 
+        {
             if (property_name == "arguments") {
-                value = Value (typeof (Array));
+                value = GLib.Value (typeof(Array));
                 if (property_node.get_node_type () != Json.NodeType.ARRAY) {
                     warning ("unexpected property node type for 'arguments' %s", property_node.get_node_type ().to_string ());
                     return false;
@@ -1058,6 +1296,13 @@ namespace Lsp {
 
        public class Diagnostics : Object, Json.Serializable 
        {
+               public Diagnostics()
+               {
+                       this.diagnostics = new Gee.ArrayList<Diagnostic>((a,b) => {
+                               return a.equals(b);
+                       });
+               }
+               
                public string uri { get; set; }
 
                public int version  { get; set; default = 0; }
@@ -1072,9 +1317,12 @@ namespace Lsp {
                
                public bool deserialize_property (string property_name, out GLib.Value val, GLib.ParamSpec pspec, Json.Node property_node) {
                        if (property_name == "diagnostics") {
-                               var diags =  new Gee.ArrayList<Diagnostic> ();
+                val = GLib.Value (typeof(Gee.ArrayList));
+                               var diags =  new Gee.ArrayList<Diagnostic> ((a,b) => {
+                                       return a.equals(b);
+                               });
                                if (property_node.get_node_type () != Json.NodeType.ARRAY) {
-                                       val = diags;
+                                       val.set_object(diags);
                                        warning ("unexpected property node type for 'arguments' %s", property_node.get_node_type ().to_string ());
                                        return false;
                                }
@@ -1088,7 +1336,7 @@ namespace Lsp {
                                                //warning ("argument %u to command could not be deserialized: %s", index, e.message);
                                         
                                });
-                               val = diags;
+                               val.set_object(diags);
                                 
                                return true;
                        }