src/Palete/Gtk.vala
[app.Builder.js] / src / Palete / Gtk.vala
1 using Gtk;
2
3 namespace Palete {
4
5         
6         
7         
8         
9         public class Introspect.El : Object
10         {
11                 public enum eltype { 
12                             NS,
13                             CLASS,
14                             METHOD,
15                             PROP
16                 }
17                 
18             
19                 public eltype type;
20         }
21
22
23         public class Gtk : Palete {
24                 
25                 public Gee.ArrayList<string> package_cache;
26                 
27                 public Gtk()
28                 {
29
30
31                     
32                     base();
33                     this.name = "Gtk";
34                     var context = new Vala.CodeContext ();
35                          
36                     this.package_cache = this.loadPackages(Path.get_dirname (context.get_vapi_path("glib-2.0")));
37                     this.package_cache.add_all(
38                             this.loadPackages(Path.get_dirname (context.get_vapi_path("gee-1.0")));
39                     );
40                                 //this.load();
41                     // various loader methods..
42                       //this.map = [];
43                     //this.load();
44                     //this.proplist = {};
45                     //this.comments = { }; 
46                     // no parent...
47                 }
48               
49                 public override void  load () {
50
51                         this.loadUsageFile(BuilderApplication.configDirectory() + "/resources/GtkUsage.txt");
52          
53                      
54                 }
55                 
56                 public string doc(string what) {
57                         var ns = what.split(".")[0];
58                         var gir =  Gir.factory(ns);
59                         return   gir.doc(what);
60                         
61                     //return typeof(this.comments[ns][what]) == 'undefined' ?  '' : this.comments[ns][what];
62                 }
63
64                         // does not handle implements...
65                 public override GirObject? getClass(string ename)
66                 {
67
68                         var es = ename.split(".");
69                         var gir = Gir.factory(es[0]);
70                 
71                         return gir.classes.get(es[1]);
72                 
73                 }
74
75                 public override Gee.HashMap<string,GirObject> getPropertiesFor(string ename, string type)  
76                 {
77                         //print("Loading for " + ename);
78                     
79
80
81                                 // if (typeof(this.proplist[ename]) != 'undefined') {
82                         //print("using cache");
83                         //   return this.proplist[ename][type];
84                         //}
85                         // use introspection to get lists..
86          
87                         var es = ename.split(".");
88                         var gir = Gir.factory(es[0]);
89                 
90                         var cls = gir.classes.get(es[1]);
91                         if (cls == null) {
92                                 var ret = new Gee.HashMap<string,GirObject>();
93                                 return ret;
94                                 //throw new Error.INVALID_VALUE( "Could not find class: " + ename);
95                         
96                         }
97
98                         //cls.parseProps();
99                         //cls.parseSignals(); // ?? needed for add handler..
100                         //cls.parseMethods(); // ?? needed for ??..
101                         //cls.parseConstructors(); // ?? needed for ??..
102
103                         cls.overlayParent();
104
105                         switch  (type) {
106                                 case "props":
107                                         return cls.props;
108                                 case "signals":
109                                         return cls.signals;
110                                 case "methods":
111                                         return cls.methods;
112                                 case "ctors":
113                                         return cls.ctors;
114                                 default:
115                                         throw new Error.INVALID_VALUE( "getPropertiesFor called with: " + type);
116                                         //var ret = new Gee.HashMap<string,GirObject>();
117                                         //return ret;
118                                 
119                         }
120                                 
121                         
122                         //cls.overlayInterfaces(gir);
123                     
124                     
125                      
126                 }
127                 public string[] getInheritsFor(string ename)
128                 {
129                         string[] ret = {};
130                          
131                         var cls = Gir.factoryFqn(ename);
132                          
133                         if (cls == null || cls.nodetype != "Class") {
134                                 print("getInheritsFor:could not find cls: %s\n", ename);
135                                 return ret;
136                         }
137                         
138                         return cls.inheritsToStringArray();
139                         
140
141                 }
142          
143                 public override void fillPack(JsRender.Node node,JsRender.Node parent)
144                 {   
145                         
146                         string inherits =  string.joinv(" ", 
147                                       this.getInheritsFor (node.fqn())) + " ";
148                         inherits += node.fqn() + " ";
149                         //print ("fillPack:Inherits : %s\n", inherits);
150                         // parent.fqn() method ( node.fqn()
151                         var methods = this.getPropertiesFor (parent.fqn(), "methods");
152                         
153                         var res = new Gee.HashMap<string,string>();
154                         var map = methods.map_iterator();
155                         while (map.next()) {
156                                 
157                                 var n = map.get_key();
158                                 //print ("fillPack:checking method %s\n", n);
159                                 
160                                 var meth = map.get_value();
161                                 if (meth.paramset == null || meth.paramset.params.size < 1) {
162                                         print ("fillPack:c -- no params\n");
163                                 
164                                         continue;
165                                 }
166                                 var fp = meth.paramset.params.get(0);
167                                 
168                                 var type = Gir.fqtypeLookup(fp.type, meth.ns);
169                                 print ("fillPack:first param type is %s\n", type);
170
171                                 
172                                 if (!inherits.contains(" " + type + " ")) {
173                                         continue;
174                                 }
175                                 
176                                 
177                                 var pack = meth.name;
178                                 for(var i =1; i < meth.paramset.params.size; i++) {
179                                         var ty = Gir.fqtypeLookup(meth.paramset.params.get(i).type, meth.ns);
180                                         pack += "," + Gir.guessDefaultValueForType(ty);
181                                 }
182
183                                 print ("fillPack:add pack:  --          %s\n",pack );
184
185                                 res.set(meth.name, pack);
186                                 
187                                 
188
189                         }
190                         if (res.size < 1) {
191                                 return ;
192                         }
193                         if (res.has_key("pack_start")) {
194                                 node.props.set("* pack", res.get("pack_start"));
195                                 return;
196                         }
197                         if (res.has_key("add")) {
198                                 node.props.set("* pack", res.get("add"));
199                                 return;
200                         }
201                         var riter = res.map_iterator();
202                         while(riter.next()) {
203                                 node.props.set("* pack", riter.get_value());
204                                 return;
205                         }
206                         
207                         
208                 }
209                 public Gee.ArrayList<string> packages(Project.Gtk gproject)
210                 {
211                         var vapidirs = gproject.vapidirs();
212                         var ret =  new Gee.ArrayList<string>();
213                         ret.add_all(this.package_cache);
214                         for(var i = 0; i < vapidirs.length;i++) {
215                                 var add = this.loadPackages(vapidirs[i]);
216                                 for (var j=0; j < add.size; j++) {
217                                         if (ret.contains(add.get(j))) {
218                                                 continue;
219                                         }
220                                         ret.add(add.get(j));
221                                 }
222                                 
223                         }
224                         
225                         return ret;
226                 }
227                 
228                 public  Gee.ArrayList<string>  loadPackages(string dirname)
229                 {
230
231                         var ret = new  Gee.ArrayList<string>();
232                         //this.package_cache = new Gee.ArrayList<string>();
233                         
234                         if (!GLib.FileUtils.test(dirname,  FileTest.IS_DIR)) {
235                                 print("opps package directory %s does not exist", dirname);
236                                 return ret;
237                         }
238                          
239                         var dir = File.new_for_path(dirname);
240                         
241                         
242                         try {
243                                 var file_enum = dir.enumerate_children(
244                                         GLib.FileAttribute.STANDARD_DISPLAY_NAME, 
245                                         GLib.FileQueryInfoFlags.NONE, 
246                                         null
247                                 );
248                         
249                          
250                                 FileInfo next_file; 
251                                 while ((next_file = file_enum.next_file(null)) != null) {
252                                         var fn = next_file.get_display_name();
253                                         if (!Regex.match_simple("\\.vapi$", fn)) {
254                                                 continue;
255                                         }
256                                         ret.add(Path.get_basename(fn).replace(".vapi", ""));
257                                 }       
258                         } catch(Error e) {
259                                 print("oops - something went wrong scanning the packages\n");
260                         }
261                         return ret;
262                         
263                          
264                 }
265                 public override bool  typeOptions(string fqn, string key, string type, out string[] opts) 
266                 {
267                         opts = {};
268                         print("get typeOptions %s (%s)%s", fqn, type, key);
269                         if (type.up() == "BOOL" || type.up() == "BOOLEAN") {
270                                 opts = { "true", "false" };
271                                 return true;
272                         }
273                         var gir= Gir.factoryFqn(type) ;
274                         if (gir == null) {
275                                 print("could not find Gir data for %s\n", key);
276                                 return false;
277                         }
278                         print ("Got type %s", gir.asJSONString());
279                         if (gir.nodetype != "Enum") {
280                                 return false;
281                         }
282                         string[] ret = {};
283                         var iter = gir.consts.map_iterator();
284                         while(iter.next()) {
285                                 
286                                 ret  += (type + "." + iter.get_value().name);
287                         }
288                         
289                         if (ret.length > 0) {
290                                 opts = ret;
291                                 return true;
292                         }
293                         
294                          
295                         return false;
296                          
297                 }
298                 
299                 public override  List<SourceCompletionItem> suggestComplete(
300                                 JsRender.JsRender file,
301                                 JsRender.Node? node,
302                                 string proptype, 
303                                 string key,
304                                 string complete_string
305                 ) { 
306                         
307                         var ret =  new List<SourceCompletionItem>();
308                         // completion rules??
309                         
310                         // make sure data is loaded
311                         Gir.factory("Gtk");
312                         
313                         // Roo......
314                         
315                         // this. (based on the node type)
316                         // this.xxx // Node and any determination...
317                         
318                         if (complete_string.index_of(".",0) < 0) {
319                                 // string does not have a '.'
320                                 // offer up vala keywords... / _this .. / look for var string = .. in the code..
321                                 
322                                 var max = (int)Vala.TokenType.YIELD +1;
323                                 for (var i =0; i < max;i++) {
324                                         var m = (Vala.TokenType)i;
325                                         var s = m.to_string();
326                                         var ss = s.slice(1,-1);
327                                         if (s[0] == '`' && GLib.Regex.match_simple("^[a-z]+$", ss) &&
328                                                 complete_string != ss && ss.index_of(complete_string,0) == 0 ) {
329                                                 ret.append(new SourceCompletionItem (ss, ss, null, "vala : " + ss));
330                                         }
331                                 }
332                                 var miter = Gir.cache.map_iterator();
333                                 while (miter.next()) {
334                                         var ss = miter.get_key();
335                                         
336                                         if (complete_string != ss && ss.index_of(complete_string,0) == 0 ) {
337                                                 ret.append(new SourceCompletionItem (ss, ss, null, "vala namespace : " + ss));
338                                         }
339                                 }
340                                  
341                                 
342                                 if (complete_string != "_this" && "_this".index_of(complete_string,0) == 0 ) { // should we ignore exact matches... ???
343                                         ret.append(new SourceCompletionItem ("_this - the top level element", "_this", null, "Top level element"));
344                                 }
345                                 // basic types..
346                                 
347                                 return ret;
348                         }
349                          
350                         
351                          // got at least one ".".
352                         var parts = complete_string.split(".");
353                         var curtype = "";
354                         var cur_instance = false;
355                         if (parts[0] == "this") {
356                                 // work out from the node, what the type is...
357                                 if (node == null) {
358                                         print("node is empty - no return\n");
359                                         return ret; // no idea..
360                                 }
361                                 curtype = "*" +  node.fqn();
362                                 cur_instance = true;
363                         } else {
364                                  if (Gir.cache.get(parts[0]) == null) {
365                                         return ret;
366                                 }
367                                 curtype = parts[0];
368                         }
369                         // all Gtk.... etc.. types...
370                         
371                         
372                         //if (parts[0] == "Roo") {      
373                         //      curtype = "Roo";
374                         //      cur_instance = false;
375                         //}
376                         
377                         var prevbits = parts[0] + ".";
378                         for(var i =1; i < parts.length; i++) {
379                                 print("matching %d/%d\n", i, parts.length);
380                                 var is_last = i == parts.length -1;
381                                 
382                                 
383                                  
384                                 // look up all the properties of the type...
385                                 var cls = Gir.factoryFqn(curtype);
386                                 if (cls == null && curtype[0] != '*') {
387                                         print("could not get class of curtype %s\n", curtype);
388                                         return ret;
389                                 }
390
391                                 if (!is_last) {
392                                         
393                                         if (curtype[0] == '*' && parts[i] == "el") {
394                                                 curtype = curtype.substring(1);
395                                                 prevbits += parts[i] + ".";
396                                                 continue;
397                                         }
398                                         
399                                         // only exact matches from here on...
400                                         if (cur_instance) {
401                                                 if (cls == null) {
402                                                         return ret;
403                                                 }
404                                                 if (cls.props.has_key(parts[i])) {
405                                                         var prop = cls.props.get(parts[i]);
406                                                         if (prop.type.index_of(".",0) > -1) {
407                                                                 // type is another roo object..
408                                                                 curtype = prop.type;
409                                                                 prevbits += parts[i] + ".";
410                                                                 continue;
411                                                         }
412                                                         return ret;
413                                                 }
414                                                  
415                                                 
416                                                 
417                                                 // check methods?? - we do not export that at present..
418                                                 return ret;      //no idea...
419                                         }
420                                         var look = prevbits + parts[i];
421                                         var scls = Gir.factoryFqn(look);
422                                         if (scls == null) {
423                                                 return ret;
424                                         }
425                                         curtype = look;
426                                         prevbits += parts[i] + ".";
427                                         continue;
428                                          
429                                 }
430                                 
431                                 // got to the last element..
432                                 print("Got last element\n");
433                                 if (curtype == "") { // should not happen.. we would have returned already..
434                                         return ret;
435                                 }
436                                 print("Got last element type %s\n",curtype);
437                                 if (!cur_instance) {
438                                         print("matching instance");
439                                         // it's a static reference..
440                                         var citer = cls.classes.map_iterator();
441                                         while (citer.next()) {
442                                                 var scls = citer.get_key();
443                                                 
444                                                 if (parts[i].length > 0 && scls.index_of(parts[i],0) != 0) {
445                                                         continue;
446                                                 }
447                                                 // got a starting match..
448                                                 ret.append(new SourceCompletionItem (
449                                                         prevbits + scls,
450                                                         prevbits + scls, 
451                                                         null, 
452                                                         scls));
453                                         }
454                                         // methods.... 
455                                         citer = cls.methods.map_iterator();
456                                         while (citer.next()) {
457                                                 var scls = citer.get_key();
458                                                 
459                                                 if (parts[i].length > 0 && scls.index_of(parts[i],0) != 0) {
460                                                         continue;
461                                                 }
462                                                 // got a starting match..
463                                                 ret.append(new SourceCompletionItem (
464                                                         prevbits + scls  + citer.get_value().sig ,
465                                                         prevbits + scls, 
466                                                         null, 
467                                                         scls));
468                                         }
469                                         
470                                         // enums.... 
471                                         citer = cls.consts.map_iterator();
472                                         while (citer.next()) {
473                                                 var scls = citer.get_key();
474                                                 
475                                                 if (parts[i].length > 0 && scls.index_of(parts[i],0) != 0) {
476                                                         continue;
477                                                 }
478                                                 // got a starting match..
479                                                 ret.append(new SourceCompletionItem (
480                                                         prevbits + scls  + citer.get_value().sig ,
481                                                         prevbits + scls, 
482                                                         null, 
483                                                         scls));
484                                         }
485                                         
486                                         
487                                         return ret;
488                                 }
489                                 print("matching property");
490                                 if (cls == null) {
491                                         return ret;
492                                 }
493                                 
494                                 
495                                 var citer = cls.methods.map_iterator();
496                                 while (citer.next()) {
497                                         var prop = citer.get_value();
498                                         // does the name start with ...
499                                         if (parts[i].length > 0 && prop.name.index_of(parts[i],0) != 0) {
500                                                 continue;
501                                         }
502                                         // got a matching property...
503                                         // return type?
504                                         ret.append(new SourceCompletionItem (
505                                                          prop.name + prop.sig + " :  ("+ prop.propertyof + ")", 
506                                                         prevbits + prop.name + "(", 
507                                                         null, 
508                                                         prop.doctxt));
509                                 }
510                                 
511                                 // get the properties / methods and subclasses.. of cls..
512                                 // we have cls.. - see if the string matches any of the properties..
513                                 citer = cls.props.map_iterator();
514                                 while (citer.next()) {
515                                         var prop = citer.get_value();
516                                         // does the name start with ...
517                                         if (parts[i].length > 0 && prop.name.index_of(parts[i],0) != 0) {
518                                                 continue;
519                                         }
520                                         // got a matching property...
521                                         
522                                         ret.append(new SourceCompletionItem (
523                                                          prop.name + " : " + prop.type + " ("+ prop.propertyof + ")", 
524                                                         prevbits + prop.name, 
525                                                         null, 
526                                                         prop.doctxt));
527                                 }
528                                          
529                                         
530                                 return ret;     
531                                         
532                                         
533                                 
534                                         
535                                 
536                         }
537                         
538                          
539                         
540                         
541                         
542                         
543                         return ret;
544                 }
545         
546     }
547 }
548