fix #7968 - language server support for syntax check and completion
[roobuilder] / src / Palete / Roo.vala
index 6848c35..e0b9131 100644 (file)
@@ -22,15 +22,22 @@ namespace Palete {
 */
     public class Roo : Palete {
                
-               
+               Gee.ArrayList<string> top_classes;
+               public static Gee.HashMap<string,GirObject>? classes_cache = null;
+               public static Gee.ArrayList<string>? top_classes_cache = null;
         public Roo(Project.Project project)
         {
 
 
             
-            base(project);
+            aconstruct(project);
             this.name = "Roo";
-                         
+                       this.top_classes =  new Gee.ArrayList<string>();
+                       
+                       this.load(); // ? initialize the roodata?
+
         }
 
                Gee.HashMap<string,GirObject> propsFromJSONArray(string type, Json.Array ar, GirObject cls)
@@ -49,6 +56,8 @@ namespace Palete {
                                if (prop.propertyof.length < 1)  {
                                        prop.propertyof = cls.name;
                                }
+                               
+                               // this is the function default.
                                prop.sig = o.has_member("sig") ? o.get_string_member("sig") : "";
                                
                                if (o.has_member("optvals")  ) {
@@ -60,44 +69,144 @@ namespace Palete {
                                        
                                }       
                                
-                               
-                               
                                //print(type + ":" + name +"\n");
                                ret.set(name,prop);
                        }
                        return ret;
                }
-        
+               
+               
                public override void  load () {
 
                        if (this.classes != null) {
                                return;
                        }
-                       this.loadUsageFile(BuilderApplication.configDirectory() + "/resources/RooUsage.txt");
+                       if (Roo.classes_cache != null) {
+                               this.classes = Roo.classes_cache;
+                               this.top_classes = Roo.top_classes_cache ;
+                               return;
+                       }
+                       
+                       
+                       // this.loadUsageFile(BuilderApplication.configDirectory() + "/resources/RooUsage.txt");
                        this.classes = new Gee.HashMap<string,GirObject>();
-
+                       var add_to =  new Gee.HashMap<string,Gee.ArrayList<string>>();
                                
                        var pa = new Json.Parser();
-                       pa.load_from_file(BuilderApplication.configDirectory() + "/resources/roodata.json");
+                       try { 
+                               pa.load_from_file(BuilderApplication.configDirectory() + "/resources/roodata.json");
+                       } catch(GLib.Error e) {
+                               GLib.error("Could not load %s",BuilderApplication.configDirectory() + "/resources/roodata.json");
+                       }
                        var node = pa.get_root();
 
                        var clist =  node.get_object(); /// was in data... .get_object_member("data");
-                               clist.foreach_member((o , key, value) => {
+                       clist.foreach_member((o , key, value) => {
                                //print("cls:" + key+"\n");
                         
                                var cls = new GirObject("class", key);  
                                cls.props = this.propsFromJSONArray("prop", value.get_object().get_array_member("props"),cls);
                                cls.signals = this.propsFromJSONArray("signal", value.get_object().get_array_member("events"),cls);
+                               
+                               
                                if (value.get_object().has_member("methods")) {
                                        cls.methods = this.propsFromJSONArray("method", value.get_object().get_array_member("methods"),cls);
                                }
+                               if (value.get_object().has_member("implementations")) {
+                                       var vcn = value.get_object().get_array_member("implementations");
+                                       for (var i =0 ; i < vcn.get_length(); i++) {
+                                               cls.implementations.add(vcn.get_string_element(i));
+                                               //break; << why!?!
+                                       }                               
+                               }
+                               // tree children = 
                                
-                               this.classes.set(key, cls);
-                       });
+                               if (value.get_object().has_member("tree_children")) {
+                                       var vcn = value.get_object().get_array_member("tree_children");                         
+                                       for (var i =0 ; i < vcn.get_length(); i++) {
+                                               var ad_c = vcn.get_string_element(i);
+                                               if (!cls.valid_cn.contains(ad_c)) {
+                                                       cls.valid_cn.add( ad_c );
+                                               }
+                                               if (!add_to.has_key(ad_c)) {
+                                                       add_to.set(ad_c, new Gee.ArrayList<string>());
+                                               }
+                                               if (!add_to.get(ad_c).contains(cls.name)) {
+                                                       add_to.get(ad_c).add(cls.name);
+                                               }
+                                       }
+                               }
+                               
                                
                                
+                               
+                               // tree parent
+                               
+                               if (value.get_object().has_member("tree_parent")) {
+                                       var vcn = value.get_object().get_array_member("tree_parent");
+                                       for (var i =0 ; i < vcn.get_length(); i++) {
+                                               if ("builder" == vcn.get_string_element(i)) {
+                                                       // this class can be added to the top level.
+                                                       GLib.debug("Add %s to *top", cls.name);
+                                                       
+                                                       this.top_classes.add(cls.name);
+                                                       break;
+                                               }
+                                               
+                                       }
+                               }
+                               this.classes.set(key, cls);
+                       });
+                       
+                       // look for properties of classes, that are atually clasess
+                       // eg. Roo.data.Store has proxy and reader..
+                       
                        
+                       foreach(var cls in this.classes.values) {
+                               foreach(var gir_obj in cls.props.values) {
+                                       var types = gir_obj.type.split("|");
+                                       for(var i =0; i < types.length; i++) {
+                                               var type = types[i];
+                                       
+                                               if (/^Roo\./.match(type) && classes.has_key(type)) {
+                                                       
+                                                        
+                                                       cls.valid_cn.add(type + ":" +   gir_obj.name );
+                                                       // Roo.bootstrap.panel.Content:east
+                                                       // also means that  Roo.bootstrap.panel.Grid:east works
+                                                       var prop_type = classes.get(type);
+                                                       foreach(var imp_str in prop_type.implementations) {
+                                                               //GLib.debug("addChild for %s - child=  %s:%s", cls.name, imp_str, gir_obj.name);
+                                                               cls.valid_cn.add(imp_str + ":" +    gir_obj.name);
+                                                               if (!add_to.has_key(imp_str)) {
+                                                                       add_to.set( imp_str, new Gee.ArrayList<string>());
+                                                               }
+                                                               if (!add_to.get( imp_str).contains(cls.name)) {
+                                                                       add_to.get( imp_str ).add(cls.name );
+                                                               }
+                                                               
+                                                       }
+                                                       
+                                                       
+                                                       if (!add_to.has_key( type)) {
+                                                               add_to.set( type, new Gee.ArrayList<string>());
+                                                       }
+                                                       if (!add_to.get(type).contains(cls.name)) {
+                                                               add_to.get( type ).add(cls.name );
+                                                       }
+                                               }
+                                       }
+                               }
                                 
+                       }
+                       foreach(var cls in this.classes.values) {
+                               if (add_to.has_key(cls.name)) {
+                                       cls.can_drop_onto = add_to.get(cls.name);
+                               }
+                       }
+                       Roo.classes_cache = this.classes;
+                       Roo.top_classes_cache  = this.top_classes;
                }
                  
                        
@@ -123,7 +232,9 @@ namespace Palete {
                        
                }
                
-               public override Gee.HashMap<string,GirObject> getPropertiesFor(string ename, string type)
+                
+               
+               public override Gee.HashMap<string,GirObject> getPropertiesFor(string ename, JsRender.NodePropType ptype)
                {
                        //print("Loading for " + ename);
                        
@@ -152,19 +263,19 @@ namespace Palete {
 
                        //cls.overlayParent();
 
-                       switch  (type) {
+                       switch  (ptype) {
                                
                                
-                               case "props":
-                                       return cls.props;
-                               case "signals":
+                               case JsRender.NodePropType.PROP:
+                                       return  this.filterProps(cls.props);
+                               case JsRender.NodePropType.LISTENER:
                                        return cls.signals;
-                               case "methods":
+                               case JsRender.NodePropType.METHOD:
                                        return ret;
-                               case "ctors":
+                               case JsRender.NodePropType.CTOR:
                                        return ret;
                                default:
-                                       throw new Error.INVALID_VALUE( "getPropertiesFor called with: " + type);
+                                       GLib.error( "getPropertiesFor called with: " + ptype.to_string()); 
                                        //var ret = new Gee.HashMap<string,GirObject>();
                                        //return ret;
                        
@@ -176,6 +287,45 @@ namespace Palete {
 
                         
                }
+               
+               // removes all the properties where the type contains '.' ?? << disabled now..
+               
+               public Gee.HashMap<string,GirObject>  filterProps(Gee.HashMap<string,GirObject> props)
+               {
+                       // we shold probably cache this??
+                       
+                       var outprops = new Gee.HashMap<string,GirObject>(); 
+                       
+                       foreach(var k in props.keys) {
+                               var val = props.get(k);
+                               
+                               // special props..
+                               switch(k) {
+                                       case "listeners" : 
+                                               continue;
+                                       default:
+                                               break;
+                               }
+                               
+                                
+                                //if (!val.type.contains(".")) {
+                                       outprops.set(k,val);
+                                       continue;
+                                //}
+                               
+                               
+                                
+                               // do nothing? - classes not allowed?
+                               
+                       }
+                       
+                       
+                       return outprops;
+               
+               
+               }
+               
+               
                public string[] getInheritsFor(string ename)
                {
                        string[] ret = {};
@@ -191,12 +341,7 @@ namespace Palete {
 
                }
 
-
-               public override void fillPack(JsRender.Node node,JsRender.Node parent)
-               {   
-
-                        return;
-               }
                /*
                 *  Pulldown options for type
                 */
@@ -209,7 +354,7 @@ namespace Palete {
                                return true;
                         }
                         
-                        var props = this.getPropertiesFor(fqn, "props");
+                        var props = this.getPropertiesFor(fqn, JsRender.NodePropType.PROP);
                         if (!props.has_key(key)) {
                                 print("prop %s does not have key %s\n", fqn, key);
                                 return false;
@@ -228,15 +373,16 @@ namespace Palete {
                         return true;
                         
                }
-               public override  List<SourceCompletionItem> suggestComplete(
+               public override  Gee.ArrayList<CompletionProposal> suggestComplete(
                                JsRender.JsRender file,
                                JsRender.Node? node,
-                               string proptype, 
-                               string key,
+                               JsRender.NodeProp? xxprop,
                                string complete_string
                ) { 
                        
-                       var ret =  new List<SourceCompletionItem>();
+                       var ret =  new Gee.ArrayList<CompletionProposal>();
+                       return ret;
+                       /*
                        // completion rules??
                        
                        // Roo......
@@ -249,17 +395,28 @@ namespace Palete {
                                // offer up this / Roo / javascript keywords... / look for var string = .. in the code..
                                for(var i = 0; i <  JsRender.Lang.match_strings.size ; i++) {
                                        var str = JsRender.Lang.match_strings.get(i);
-                                       if (complete_string != str && str.index_of(complete_string,0) == 0 ) { // should we ignore exact matches... ???
-                                               ret.append(new SourceCompletionItem (str, str, null, "javascript : " + str));
+                                       if (complete_string != str && str.index_of(complete_string,0) == 0 ) { 
+                                               // should we ignore exact matches... ???tr,str,
+                                               var sci = new CompletionProposal(str,str, "javascript: " + str);
+                                               ret.add(sci);
+                                                
                                        }
                                        
                                        
                                }
-                               if (complete_string != "Roo" && "Roo".index_of(complete_string,0) == 0 ) { // should we ignore exact matches... ???
-                                       ret.append(new SourceCompletionItem ("Roo - A Roo class", "Roo", null, "Roo library"));
+                               if (complete_string != "Roo" && "Roo".index_of(complete_string,0) == 0 ) { 
+                                       // should we ignore exact matches... ???
+                               
+                                       var sci = new CompletionProposal("Roo - A Roo class","Roo", "Roo Library");
+                                       ret.add(sci);
+                                
                                }
-                               if (complete_string != "_this" && "_this".index_of(complete_string,0) == 0 ) { // should we ignore exact matches... ???
-                                       ret.append(new SourceCompletionItem ("_this - the top level element", "_this", null, "Top level element"));
+                               if (complete_string != "_this" && "_this".index_of(complete_string,0) == 0 ) { 
+                                       // should we ignore exact matches... ???
+                                       var sci = new CompletionProposal("_this - Reference to the global pointer to the files main class instance",
+                                               "_this", "Reference to the global pointer to the files main class instance");
+                                       ret.add(sci);
+                                        
                                }
                                return ret;
                        }
@@ -352,12 +509,10 @@ namespace Palete {
                                                if (parts[i].length > 0 && scls.index_of(look,0) != 0) {
                                                        continue;
                                                }
+                                               
                                                // got a starting match..
-                                               ret.append(new SourceCompletionItem (
-                                                       scls,
-                                                       scls, 
-                                                       null, 
-                                                       scls));
+                                               var sci = new CompletionProposal(scls,scls,scls);
+                                               ret.add(sci);
                                        }
                                        return ret;
                                }
@@ -374,11 +529,12 @@ namespace Palete {
                                        }
                                        // got a matching property...
                                        // return type?
-                                       ret.append(new SourceCompletionItem (
-                                                        prop.name + prop.sig + " :  ("+ prop.propertyof + ")", 
-                                                       prevbits + prop.name + "(", 
-                                                       null, 
-                                                       prop.doctxt));
+                                       
+                                       
+                                       var sci = new CompletionProposal(prop.name + prop.sig + " :  ("+ prop.propertyof + ")",
+                                               prevbits + prop.name + "(",prop.doctxt);
+                                       ret.add(sci);
+                                        
                                }
                                
                                // get the properties / methods and subclasses.. of cls..
@@ -390,13 +546,11 @@ namespace Palete {
                                        if (parts[i].length > 0 && prop.name.index_of(parts[i],0) != 0) {
                                                continue;
                                        }
-                                       // got a matching property...
-                                       
-                                       ret.append(new SourceCompletionItem (
-                                                        prop.name + " : " + prop.type + " ("+ prop.propertyof + ")", 
-                                                       prevbits + prop.name, 
-                                                       null, 
-                                                       prop.doctxt));
+                                       // got a matching property..
+                                       var sci = new CompletionProposal(prop.name + prop.type + " :  ("+ prop.propertyof + ")",
+                                               prevbits + prop.name + "(",prop.doctxt);
+                                       ret.add(sci);
+                               
                                }
                                         
                                        
@@ -414,7 +568,97 @@ namespace Palete {
                        
                        
                        return ret;
+                       */
                }
+               
+               
+               public override Gee.ArrayList<string> getChildList(string in_rval, bool with_prop)
+        {
+               if (this.top_classes.size < 1) {
+                       this.load();
+               }
+                
+                
+                
+               var ar = this.top_classes;
+               if (in_rval != "*top") {
+                       if (this.classes.has_key(in_rval)) {
+                          // some of these children will be eg: Roo.bootstrap.layout.Region:center
+                               ar = this.classes.get(in_rval).valid_cn;
+                       } else {
+                               ar = new Gee.ArrayList<string>();
+                       }
+               }
+               
+               if (!with_prop) {
+                       var ret = new Gee.ArrayList<string>();
+                       foreach(var v in ar) {
+                               if (v.contains(":")) {
+                                       continue;
+                               }
+                               ret.add(v);
+                       }
+                       return ret;
+               }
+                
+               GLib.debug("getChildList for %s returns %d items",  in_rval, ar.size);
+               return ar;      
+               
+               //return this.original_getChildList(  in_rval);
+       }
+       
+
+       
+               public override Gee.ArrayList<string> getDropList(string rval)
+               {
+                       
+                       if (this.dropCache.has_key(rval)) {
+                               return this.dropCache.get(rval);
+                       }
+                       // we might be dragging  Roo.bootstrap.layout.Region:center
+                       // in which case we need to lookup Roo.bootstrap.layout.Region
+                       // and see if it's has can_drop_onto
+                       var  ret = new Gee.ArrayList<string>();
+                       var cls = this.classes.get(rval);
+                       // cls can be null.
+                       if (cls == null && rval.contains(":")) {
+                               var rr = rval.substring(0,rval.index_of(":"));
+                               GLib.debug("Converted classname to %s", rr);
+                               cls = this.classes.get(rr);
+                   }
+                       if (cls == null) {
+                               return ret; //nothing..
+                       }
+                       
+                       foreach(var str in cls.can_drop_onto) {
+
+                               ret.add(str);
+                       }
+                       //GLib.debug("getDropList for %s return[] %s", rval, string.joinv(", ", ret));
+                       this.dropCache.set(rval,ret);
+                       return ret;
+                               
+                       
+                       
+                       //return this.default_getDropList(rval);
+               }       
+               public override JsRender.Node fqnToNode(string fqn) 
+               {
+                       var ret = new JsRender.Node();
+                       ret.setFqn(fqn);
+                       // any default requred proerties?
+                       
+                       return ret;
+                       
+                       
+                       
+               }
+               
     }
+    
+    
+               
+               
+    
 }