meson.build.o7QLX02
[roobuilder] / src / Project / Project.vala
1 //<Script type="text/javascript">
2
3 /**
4  * Project Object
5  * 
6  * Projects can only contain one directory... - it can import other projects..(later)
7  * 
8  * we need to sort out that - paths is currently a key/value array..
9  * 
10  * currently we store projects in ~/.Builder/{md5}.json
11    - then for Gtk projects we have a file config1.builder - which contains dependancies, and a list of files for each target
12      (for builder it's ended up in src/Builder/config1.builder? by accident.
13    - should really support something like 
14        roobuilder --build {path_to_cfg} {target} - or local directory if not set..
15        roobuilder --build-errors {path_to_cfg} {target} - or local directory if not set..
16        
17        
18    
19    
20    should really store project data in the directory of the project?
21    
22    
23    // steps:
24    // List of projects - just an array of paths in .Builder/Projects.json
25    
26    // .roobuilder.jcfg  << hidden file with project details?
27    
28    
29    
30  
31  * 
32  * 
33  */
34 namespace Project {
35          public errordomain Error {
36                 INVALID_TYPE,
37                 NEED_IMPLEMENTING,
38                 MISSING_FILE,
39                 INVALID_VALUE,
40                 INVALID_FORMAT
41         }
42
43
44         
45         // static array of all projects.
46         private Gee.ArrayList<Project>  projects;
47         
48         
49         
50         public bool  projects_loaded = false;
51         
52         
53         // used to pass around callbacks with project as a return
54         public class Callback : Object {
55                 public signal void call(Project project);
56         }
57         
58         public abstract class Project : Object {
59                 
60                 public signal void on_changed (); 
61         
62                 //public string id;
63                 //public string fn = ""; // just a md5...
64                 public string name  { 
65                         private set {} 
66                         owned get {
67                                 return GLib.Path.get_basename(path);
68                         }
69                          
70                 }
71                                 
72                 
73                 public string path = "";
74                 private Gee.ArrayList<JsRender.JsRender> sub_paths;
75                 
76                 private Gee.HashMap<string,JsRender.JsRender> files ;  // contains full list of files.
77                 //tree : false,
78                 public  string xtype;
79                 
80                 //public Json.Object json_project_data;
81
82                 public Palete.Palete palete;
83                  
84                 private bool is_scanned = false; 
85                 public  Gee.HashMap<string,Palete.GirObject> gir_cache = null; // used by Gir ??? is this used by Roo?
86                 //public Palete.ValaCompileRequest last_request = null; // depricated?
87                 public Gee.HashMap<string,GLib.ListStore>? errorsByType = null;
88  
89                 
90                 
91                 protected Gee.HashMap<string,Palete.LanguageClient> language_servers;
92                 
93                 protected Project (string path) {
94                         
95                          
96                         //this.json_project_data = new Json.Object();
97                         
98                         this.is_scanned = false;
99                         this.sub_paths = new Gee.ArrayList<JsRender.JsRender>();
100                         this.files = new Gee.HashMap<string,JsRender.JsRender>();
101                         //XObject.extend(this, cfg);
102                         //this.files = { }; 
103                         this.path = path;
104                         this.language_servers = new Gee.HashMap<string,Palete.LanguageClient>();
105                         this.language_servers.set("dummy", new Palete.LanguageClientDummy(this));
106                         this.errorsByType = new  Gee.HashMap<string,GLib.ListStore>();
107                         
108                 }
109                  
110                 
111                 
112                 
113                 public static void loadAll(bool force = false)
114                 {
115                         if (projects_loaded && !force) {
116                                 return;
117                         }
118
119                         var dirname = GLib.Environment.get_home_dir() + "/.Builder";
120                         var dir = File.new_for_path(dirname);
121                         if (!dir.query_exists()) {
122                                 try {
123                                         dir.make_directory();
124                                 } catch(GLib.Error e) {
125                                         GLib.error("could not make builder directory %s", e.message);
126                                 }
127                                 return;
128                         }
129                         projects = new  Gee.ArrayList<Project>();
130                           
131                     
132                     if (FileUtils.test(dirname + "/Projects.list", GLib.FileTest.IS_REGULAR)) {
133                         loadProjectList();
134                         projects_loaded = true;
135                         return;
136                 }
137                 convertOldProjects(); // this saves..
138                 foreach(var p in projects) {
139                         p.save();
140                 }
141                         projects_loaded = true;
142  
143         }
144          
145         public static void remove(Project p) {
146                 projects.remove(p);
147                 saveProjectList();
148         
149         }
150         
151         public static void saveProjectList()
152         {
153                         var f = new Json.Object();
154                         foreach(var p in projects) {
155                                 f.set_string_member(p.path, p.xtype);
156                         }
157                         
158                         var  generator = new Json.Generator ();
159                         var  root = new Json.Node(Json.NodeType.OBJECT);
160                         root.init_object(f);
161                         generator.set_root (root);
162                         generator.pretty = true;
163                         generator.indent = 4;
164
165                         var data = generator.to_data (null);
166                         var dirname = GLib.Environment.get_home_dir() + "/.Builder";
167                 GLib.debug("Write new Project list\n %s", data);
168                 //Posix.exit(0);
169                 
170                 try {
171                                 //FileUtils.set_contents(dirname + "/" + this.fn + ".json", s, s.length);  
172                                 FileUtils.set_contents(dirname + "/Projects.list", data, data.length);  
173                         } catch (GLib.Error e) {
174                                 GLib.error("failed  to save file %s", e.message);
175                         }
176                 
177         }
178         
179         
180         
181         public static void convertOldProjects()
182         {
183         
184                         var dirname = GLib.Environment.get_home_dir() + "/.Builder";
185                         var  dir = File.new_for_path(dirname);
186                         try {
187                                 var file_enum = dir.enumerate_children(
188                                                                 GLib.FileAttribute.STANDARD_DISPLAY_NAME, 
189                                         GLib.FileQueryInfoFlags.NONE, 
190                                         null
191                                 );
192                                  
193                                 FileInfo next_file; 
194                                 while ((next_file = file_enum.next_file(null)) != null) {
195                                         var fn = next_file.get_display_name();
196                                         if (!Regex.match_simple("\\.json$", fn)) {
197                                                 continue;
198                                         }
199                                         Project.factoryFromFileOld(dirname + "/" + fn);
200                                 }       
201                         } catch(GLib.Error e) {
202                                 GLib.warning("oops - something went wrong scanning the projects\n");
203                         }
204                         GLib.debug("Loaded all old Projects - saving");
205                         Project.saveProjectList();
206
207                 }
208
209                 public static Gee.ArrayList<Project> allProjectsByName()
210                 {
211                         
212                         return projects;
213                 
214                 }
215                 
216                 public static Project? getProjectByName(string name)
217                 {
218                         
219                         foreach (var p in projects) {
220                                 if (p.name == name) {
221                                         return p;
222                                 }
223                         }
224                         
225                         return null;
226                 
227                 }
228                 public static Project? getProjectByPath(string path)
229                 {
230                         
231                         foreach (var p in projects) {
232                                 if (p.path == path) {
233                                         return p;
234                                 }
235                         }
236                         
237                         return null;
238                 
239                 }
240                 public static string listAllToString()
241                 {
242                         var all = projects;
243
244                          
245                         
246                         all.sort((fa,fb) => {
247                                 return ((Project)fa).name.collate(((Project)fb).name);
248
249                         });
250
251                         var iter = all.list_iterator();
252                         var ret = "ID\tName\tDirectory\n";
253                         while (iter.next()) {
254                                 ret += "%s\t%s\n".printf(
255                                                  
256                                                 iter.get().name,
257                                                 iter.get().path
258                                                 );
259                          
260                                 
261                         }
262                         
263                         return ret;
264                 
265                 }
266                 
267                 
268                 public static void loadIntoStore(GLib.ListStore st)
269                 {
270                         st.remove_all();
271                         foreach (var p in projects) {
272                                 st.append(p);
273                         }
274                         
275                 }
276                         
277                 
278  
279                 
280                 static void loadProjectList()
281                 {
282                 
283                         var dirname = GLib.Environment.get_home_dir() + "/.Builder";
284                          
285                         projects = new  Gee.ArrayList<Project>();
286                           
287                     var pa = new Json.Parser();
288                         try { 
289                                 pa.load_from_file(dirname + "/Projects.list");  
290                         } catch (GLib.Error e) {
291                                 GLib.error("could not load json file %s", e.message);
292                         }
293                         var node = pa.get_root();
294                         if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
295                                 GLib.error( dirname + "/Projects.list - invalid format?");
296                                  
297                         }
298
299                         
300                         var obj = node.get_object ();
301                         obj.foreach_member((sobj, key, val) => {
302                                 GLib.debug("read ProjectList %s: %s", key, val.get_string());
303                                 // facotry adds project!
304                                 try {
305                                         Project.factory(val.get_string(), key );
306                                 } catch (GLib.Error e ) {
307                                         GLib.debug("error createing project %s", e.message);
308                                 }
309                                  
310                         });
311                         
312                 
313                 }
314                 
315                 // load project data from project file.
316                 public static void   factoryFromFileOld(string jsonfile)
317                 {
318                          
319                         GLib.debug("parse %s", jsonfile);
320
321                         var pa = new Json.Parser();
322                         try { 
323                                 pa.load_from_file(jsonfile);
324                         } catch (GLib.Error e) {
325                                 GLib.error("could not load json file %s", e.message);
326                         }
327                         var node = pa.get_root();
328
329                         
330                         if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
331                                 GLib.debug("SKIP " + jsonfile + " - invalid format?");
332                                 return;
333                         }
334                         
335                         var obj = node.get_object ();
336                         var xtype =  obj.get_string_member("xtype");
337
338
339                         var paths = obj.get_object_member("paths");
340                         var i = 0;
341                         var fpath = "";
342                         paths.foreach_member((sobj, key, val) => {
343                                 if (i ==0 ) {
344                                         fpath = key;
345                                 }
346                                         
347                         });
348                         
349                         if (fpath.length < 0 || !FileUtils.test(fpath,FileTest.IS_DIR)) {
350                                 return;
351                         }
352                         
353                         Project proj;
354                         try {
355                                 proj = factory(xtype, fpath);
356                         } catch (Error e)  {
357                                 GLib.debug("Skip file - invalid file type");
358                                 return;
359                         }
360
361                         //proj.json_project_data  = obj; // store the original object...
362                         
363                         //proj.fn =  Path.get_basename(jsonfile).split(".")[0];
364
365                         proj.loadJson(obj);
366                         // might not exist?
367  
368                         proj.name = obj.get_string_member("name");
369
370                         // used to load paths..
371                         //proj.initSubDirectories();
372                         
373                          
374                         //proj.initDatabase();
375                         
376                         GLib.debug("Add Project %s", proj.name);
377                         
378                         projects.add(proj);
379                          
380                         
381                 }
382                 
383                 
384                 public static Project factory(string xtype, string path) throws Error
385                 {
386
387                         // check to see if it's already loaded..
388
389                          foreach(var p in projects) {
390                                   if (p.path == path) {
391                                         return p;
392                                  }
393                         }
394
395                         
396                         switch(xtype) {
397                                 case "Gtk":
398                                         var ret =  new Gtk(path);
399                                         projects.add(ret);
400                                         
401                                         return ret;
402                                 case "Roo":
403                                         var ret = new Roo(path);
404                                         projects.add(ret);
405                                  
406                                         return ret;
407                                 //case "Flutter":
408                                 //      return new Flutter(path);
409                         }
410                         throw new Error.INVALID_TYPE("invalid project type");
411                                 
412                 }
413                 
414                 
415          
416
417                 public void save()
418                 {
419                           
420                         var  s =  this.toJSON();
421                         GLib.debug("Save Project %s\n%s", this.name, s);
422                         try {
423                                 //FileUtils.set_contents(dirname + "/" + this.fn + ".json", s, s.length);  
424                                 FileUtils.set_contents(this.path + "/.roobuilder.jcfg", s, s.length);  
425                         } catch (GLib.Error e) {
426                                 GLib.error("failed  to save file %s", e.message);
427                         }
428                         this.onSave();
429                         
430                 }
431
432         
433                 
434                 
435                 public string toJSON( )
436                 {
437                         
438                         var obj = new Json.Object();
439                         obj.set_string_member("xtype", this.xtype);
440                                                 
441                         
442                         this.saveJson(obj);
443                 
444                         var  generator = new Json.Generator ();
445                         var  root = new Json.Node(Json.NodeType.OBJECT);
446                         root.init_object(obj);
447                         generator.set_root (root);
448                         //if (show_all) {
449                                 generator.pretty = true;
450                                 generator.indent = 4;
451                         //}
452
453                         return  generator.to_data (null);
454                           
455                           
456                 }
457                 
458                 // used to check what type a project might be..
459                 // for 'new'
460                 public static string peekProjectType(string fn) 
461                 {
462                         var pa = new Json.Parser();
463                         try { 
464                                 pa.load_from_file(fn);
465                         } catch (GLib.Error e) {
466                                 GLib.debug("could not load json file %s", e.message);
467                                 return "";
468                                 
469                         }
470                         var node = pa.get_root();
471
472                         if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
473                                 GLib.debug("SKIP %s/.roobuilder.jcfg  - invalid format?",fn);
474                                 return "";
475                         }
476                         
477                         var obj = node.get_object ();
478
479                         var xtype =  obj.get_string_member("xtype");
480                         return xtype == null ? "" : xtype;
481                 
482                 }
483                 
484                 
485                 // this will do a full scan - should only be done on viewing project..
486                 // not initial load.. - may take time.
487                 
488                 public   void   load()
489                 {
490                         if (this.is_scanned) {
491                                 return;
492                         }
493                         GLib.debug("load is_scanned = false");
494                         
495                         if (FileUtils.test(this.path + "/.roobuilder.jcfg", FileTest.EXISTS)) {
496                                   
497                                 var pa = new Json.Parser();
498                                 try { 
499                                         pa.load_from_file(this.path + "/.roobuilder.jcfg");
500                                 } catch (GLib.Error e) {
501                                         GLib.error("could not load json file %s", e.message);
502                                 }
503                                 var node = pa.get_root();
504
505                                 
506                                 if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
507                                         GLib.debug("SKIP %s/.roobuilder.jcfg  - invalid format?",this.path);
508                                         return;
509                                 }
510                                 
511                                 var obj = node.get_object ();
512                                  
513                                 this.loadJson(obj);
514                         } 
515                         // used to load paths..
516                         this.sub_paths = new Gee.ArrayList<JsRender.JsRender>();
517                         this.files = new Gee.HashMap<string,JsRender.JsRender>();
518                         this.loadSubDirectories("", 0);
519                          
520                         this.initDatabase();
521                         this.is_scanned = true; // loaded.. dont need to do it again..
522                          GLib.debug("load is_scanned = true");
523                         
524                 }
525                 
526                 
527                 /*
528                 
529                 public string firstPath()
530                 {
531                         var iter = this.paths.map_iterator();
532                         while (iter.next()) {
533                                 return iter.get_key();
534                         }
535                   
536                         return "";
537                 }
538
539                 public bool hasPath(string path)
540                 {
541                         var iter = this.paths.map_iterator();
542                         while (iter.next()) {
543                                 if (iter.get_key() == path) {
544                                 return true;
545                         }
546                         }
547                   
548                         return false;
549                 }
550
551                 
552                 // returns the first path
553                 public string getName()
554                 {
555                         var iter = this.paths.map_iterator();
556                         while (iter.next()) {
557                                 return GLib.Path.get_basename(iter.get_key());
558                         }
559                   
560                         return "";
561                 }
562                 */
563
564                 public Gee.ArrayList<JsRender.JsRender> sortedFiles()
565                 {
566                         var files = new Gee.ArrayList<JsRender.JsRender>();
567
568                         var fiter = this.files.map_iterator();
569                         while(fiter.next()) {
570                                 files.add(fiter.get_value());
571                         }
572                         files.sort((fa,fb) => {
573                                 return ((JsRender.JsRender)fa).name.collate(((JsRender.JsRender)fb).name);
574
575                         });
576                         return files;
577
578                 }
579                 
580          
581          
582                 public string listAllFilesToString()
583                 {
584                  
585                         var iter = this.sortedFiles().list_iterator();
586                         var ret = "ID\tName\tDirectory\n";
587                         while (iter.next()) {
588                                 ret += "%s\n".printf(
589                                                  
590                                                 iter.get().name
591                                                  
592                                                 );
593                          
594                                 
595                         }
596                         
597                         return ret;
598                 
599                 }
600                 
601          
602          
603          
604                 public JsRender.JsRender? getByRelPath(string relpath)
605                 {
606                         foreach(var f in this.files.values) {
607                                 if (f.relpath == relpath || f.relTargetName() == relpath) {
608                                         return f;
609                                 }
610                         };
611                         return null;
612                 }
613                 // this get's a file using the full path ( replaces vala->bjs if they exist);
614                 
615                 public JsRender.JsRender? getByPath(string path)
616                 {
617                  
618                         // keys are not paths...
619                         foreach(var f in this.files.values) {
620                                 //GLib.debug("check %s = %s ? %s", path, f.path, f.targetName());
621                                 if (f.path == path || f.targetName() == path) {
622                                         return f;
623                                 }
624                         };
625                         return null;                    
626                 }
627                 
628                 public JsRender.JsRender? getById(string id)
629                 {
630                         foreach(var f in this.files.values) {
631                                 if (f.id == id) {
632                                         return f;
633                                 }
634                         };
635                         return null;
636                 }
637  
638                 // name should include extension.       
639                 /*
640                 public JsRender.JsRender? newFile (string xtype, string sub_dir, string name)
641                 {
642                         try {
643                                 var fp = this.path + (sub_dir.length > 0  ? "/" : "") + sub_dir;
644                                 if (this.files.has_key(fp + "/" +  name)) {
645                                         return null;
646                                 }
647                                  
648                                 
649                                 var ret =  JsRender.JsRender.factory(xtype, 
650                                                                                          this, 
651                                                                                          fp + "/" +  name
652                                                                                          );
653                                 this.files.set(fp + "/" +  name , ret);
654                                 return ret;
655                         } catch (JsRender.Error e) {
656                                 GLib.error("failed to create file %s", e.message);
657                         }
658                 }
659                 */
660          
661                 public JsRender.JsRender loadFileOnly (string path)
662                 {
663                         var xt = this.xtype;
664                         try {
665                                 return JsRender.JsRender.factory(xt, this, path);
666                         } catch (JsRender.Error e) {
667                                 GLib.error("failed to create file %s", e.message);
668                         } 
669                         
670                 } 
671                 
672                 /* 
673                 public JsRender.JsRender create(string filename)
674                 {
675                         var ret = this.loadFileOnly(filename);
676                         ret.save();
677                         this.addFile(ret);
678                         return ret;
679                         
680                 }
681                 */
682                 private void loadSubDirectories(string subdir, int dp) 
683                 {
684                         //dp = dp || 0;
685                         //print("Project.Base: Running scandir on " + dir +"\n");
686                         if (dp > 5) { // no more than 5 deep?
687                                 return;
688                         }
689                         if (subdir == "build") { // cmake!
690                                 return;
691                         }
692                         
693                         if (subdir == "autom4te.cache") { // automake?
694                                 return;
695                         }
696                         if (subdir == "debian") { // debian!?
697                                 return;
698                         }
699
700                         
701                         var dir = this.path + (subdir.length > 0 ? "/" : "") + subdir;
702                         
703                         
704                         GLib.debug("Project %s Scan Dir: %s", this.name, dir);
705                         var jsDir = new JsRender.Dir(this, dir);
706                         this.sub_paths.add(jsDir); // might be ''...
707                         
708                         
709                         // this should be done async -- but since we are getting the proto up ...
710                         var other_files = new Gee.ArrayList<string>();
711                         var bjs_files = new Gee.ArrayList<string>();
712                         var vala_files = new Gee.ArrayList<string>();
713                         var subs = new Gee.ArrayList<string>();
714                         
715                         
716                         var f = File.new_for_path(dir);
717                         try {
718                                 var file_enum = f.enumerate_children(GLib.FileAttribute.STANDARD_DISPLAY_NAME, GLib.FileQueryInfoFlags.NONE, null);
719                                 
720                                  
721                                 FileInfo next_file; 
722                                 while ((next_file = file_enum.next_file(null)) != null) {
723                                         var fn = next_file.get_display_name();
724                         
725                                          
726                                         //print("trying"  + dir + "/" + fn +"\n");
727                                         
728                                         if (fn[0] == '.') { // skip hidden
729                                                 continue;
730                                         }
731                                         
732                                         if (FileUtils.test(dir  + "/" + fn, GLib.FileTest.IS_DIR)) {
733                                                 subs.add(dir  + "/" + fn);
734                                                 continue;
735                                         }
736                                         if (Regex.match_simple("\\.(o|cache|gif|jpg|png|gif|out|stamp|~)$", fn)) { // object..
737                                                 continue;
738                                         }
739                                         if (Regex.match_simple("^(config1.builder|a.out|stamp-h1|depcomp|config.log|config.status)$", fn)) { // object..
740                                                 continue;
741                                         }
742                                         
743                                         
744                                         if (Regex.match_simple("\\.vala$", fn)) {
745                                                 vala_files.add(fn);
746                                                 other_files.add(fn);
747                                                 //print("no a bjs\n");
748                                                 continue;
749                                         }
750                                         if (!Regex.match_simple("\\.bjs$", fn)) {
751                                                 other_files.add(fn);
752                                                 //print("no a bjs\n");
753                                                 continue;
754                                         }
755                                         bjs_files.add(fn.substring(0, fn.length-4));
756                                         
757                                         var xt = this.xtype;
758                                         var el = JsRender.JsRender.factory(xt,this, dir + "/" + fn);
759                                         this.files.set( dir + "/" + fn, el);
760                                         jsDir.childfiles.append(el);
761                                         
762                                         // parent ?? 
763                                         
764                                          
765                                 }
766                         } catch (Error e) {
767                                 GLib.warning("Project::scanDirs failed : " + e.message + "\n");
768                         } catch (GLib.Error e) {
769                                 GLib.warning("Project::scanDirs failed : " + e.message + "\n");
770                         } 
771
772                         foreach(var fn in other_files) {
773                                 var dpos = fn.last_index_of(".");
774                                 var without_ext = fn.substring(0, dpos);
775                                 if (bjs_files.contains(without_ext)) {  // will remove vala and c.
776                                         continue;
777                                 }
778                                 // c with a vala - skip
779                                 if (Regex.match_simple("\\.c$", fn) && vala_files.contains(without_ext + ".vala")) {
780                                         continue;
781                                 }
782                                 // Makefile (only allow am files at present.
783                                 if (without_ext == "Makefile") {
784                                         if (!Regex.match_simple("\\.am$", fn)) {
785                                                 continue;
786                                         }
787                                 }
788                                 if (without_ext == "configure") {
789                                         if (!Regex.match_simple("\\.ac$", fn)) {
790                                                 continue;
791                                         }
792                                 }
793                                 
794                                 
795                                 
796                                 
797                                 
798                                 //GLib.debug("Could have added %s/%s", dir, fn);
799                                 try {
800                                          var el = JsRender.JsRender.factory("PlainFile",this, dir + "/" + fn);
801                                          this.files.set( dir + "/" + fn, el);
802                                         jsDir.childfiles.append(el);
803                                 } catch (JsRender.Error e) {
804                                         GLib.warning("Project::scanDirs failed : " + e.message + "\n");
805                                 }
806                         }
807                         
808                         foreach (var sd in subs) {
809                                  this.loadSubDirectories(sd.substring(this.path.length+1), dp+1);
810                         }
811                         
812                 
813                 }
814                 
815                 // calle dfrom new file dialog
816                 // add files to dires (and main file list)
817                 // update 
818                         
819                  
820                 public void addFile(JsRender.JsRender pfile)
821                 { // add a single file, and trigger changed.
822                 
823                         if (pfile.xtype == "Gtk" || pfile.xtype == "Roo" ) {
824                                 this.files.set(pfile.path, pfile); // duplicate check
825                                 
826                                 if (pfile.xtype == "Gtk" && pfile.build_module != "") {
827                                 
828                                         var gfile = (JsRender.Gtk) pfile;
829                                         gfile.updateCompileGroup("", pfile.build_module);
830                                          
831                                 }
832                         }
833                         var sp = this.findDir(pfile.dir);
834                         sp.childfiles.append(pfile);    
835                         this.files.set(pfile.path, pfile);
836                         
837                         this.on_changed();
838                 }
839                 
840                 
841                 
842                 public void deleteFile(JsRender.JsRender file) 
843                 {
844                         if (file.xtype =="Dir") {
845                                 return;
846                         }
847                         var sp = this.findDir(file.dir);
848                         for(var i =0;i < sp.childfiles.n_items; i++) {
849                                 var jf = (JsRender.JsRender) sp.childfiles.get_item(i);
850                                 if (jf.path == file.path) {
851                                         sp.childfiles.remove(i);
852                                         break;
853                                 }
854                         }
855                         if (this.files.has_key(file.path)) {
856                                 this.files.unset(file.path);
857                         }
858
859                         
860                         file.remove();
861                         this.save();
862                         
863                         // remove it from 
864                         
865                         
866                 }
867                         
868                 // but do not add it to our list.!!!
869                 public void makeProjectSubdir(string name)
870                 {
871                         var dir = File.new_for_path(this.path + "/" + name);
872                         if (FileUtils.test(this.path + "/" + name, FileTest.EXISTS)) {
873                                 return;
874                         }
875                         try {
876                                  
877                                 dir.make_directory();   
878                         } catch (GLib.Error e) {
879                                 GLib.error("Failed to make directory %s", this.path + "/" + name);
880                         } 
881                 }
882                 
883                 public void createDir(string subdir)   // add a single dir, and trigger changed.
884                 {
885                         if (subdir.strip() == "" || this.subpathsContains(subdir)) {
886                                 return;
887                         }
888                         var dir= File.new_for_path(this.path + "/" + subdir);
889
890                         if (!dir.query_exists()) {
891                         
892                                 try {
893                                          
894                                         dir.make_directory();   
895                                 } catch (GLib.Error e) {
896                                         GLib.error("Failed to make directory %s", this.path + "/" + name);
897                                 }
898
899                         }
900                         this.sub_paths.add(new JsRender.Dir(this,this.path + "/" + subdir));
901                         this.on_changed();  // not sure if it's needed - adding a dir doesnt really change much.
902                 }
903                 
904                 // this store is used in the icon view ?? do we need to store and update it?
905                 public void loadFilesIntoStore(GLib.ListStore ls) 
906                 {
907                         ls.remove_all();
908                         //GLib.debug("Load files (into grid) %s", this.name);                   
909                         foreach(var f in this.files.values) {
910                         //      GLib.debug("Add file %s", f.name);
911                                 if (f.xtype == "PlainFile") {
912                                         continue;
913                                 }
914                                 ls.append(f);
915                         }
916                         
917                 }
918                 public void loadDirsIntoStore(GLib.ListStore  ls) 
919                 {
920                         ls.remove_all();
921                         foreach(var f in this.sub_paths) {
922                                 //GLib.debug("Add %s", f.name);
923                                 ls.append(f);
924                         }
925                          ;
926                 }
927                 
928                 public bool subpathsContains(string subpath) 
929                 {
930                         foreach(var sp in this.sub_paths) {
931
932                                 if (sp.path == this.path + "/" + subpath) {
933                                         return true;
934                                 }
935                         }
936                         return false;
937                         
938                 }
939                 
940                 public void loadDirsToStringList( global::Gtk.StringList sl, string prefix) 
941                 {
942                          
943                         while (sl.get_n_items() > 0) {
944                                 sl.remove(0);
945                         }
946                         
947                         foreach(var sp in this.sub_paths) {
948                                  var add = sp.path == this.path ? "/" : sp.path.substring(this.path.length);
949                                 if (prefix.length > 0 && !add.has_prefix(prefix)) {
950                                         continue;
951                                 }
952                                 sl.append(add);
953                         }
954                 
955                 }
956                 
957                 public JsRender.Dir? findDir(string path) {
958                         
959                         foreach(var jdir in this.sub_paths) { 
960                                 if (path == jdir.path) {
961                                         return (JsRender.Dir)jdir;
962                                 }
963                         }
964                         return null;
965                 }
966                 
967                 public string[] pathsMatching(string name, bool full_path)
968                 {
969                         string[] ret = {};
970                          
971                         foreach(var jdir in this.sub_paths) { 
972                                 
973
974                                 
975                                 if (Path.get_basename (jdir.path) == name) {
976                                         GLib.debug("pathsMatching %s\n", jdir.path);
977                                         ret += full_path ? jdir.path : jdir.relpath;
978                                 }
979                                 
980                         }
981                         return ret;
982                         
983                 }
984                 public Gee.ArrayList<string> readArray(Json.Array ar) 
985                 {
986                         var ret = new Gee.ArrayList<string>();
987                         for(var i =0; i< ar.get_length(); i++) {
988                                 var add = ar.get_string_element(i);
989                                 if (ret.contains(add)) {
990                                         continue;
991                                 }
992                         
993                                 ret.add(add);
994                         }
995                         return ret;
996                 }
997                 
998                 public void updateErrorsforFile(JsRender.JsRender? f) 
999                 {
1000                         if (f != null)  {
1001                                 var n = this.updateErrorsByType(f, "WARN");
1002                                 n += this.updateErrorsByType(f, "ERR");
1003                                 n += this.updateErrorsByType(f, "DEPR");
1004                         }
1005
1006                         BuilderApplication.updateCompileResults();
1007                         
1008                         
1009                 }
1010                 public int  updateErrorsByType(JsRender.JsRender f, string n) 
1011                 {
1012                         var ls = this.getErrors(n);
1013                         
1014                         // remove thie file from the list.      
1015                         for(var i =0; i < ls.get_n_items(); i++) {
1016                                 var ce = ls.get_item(i) as Palete.CompileError;
1017                                 if (ce.file.path == f.path) {
1018                                         ls.remove(i);
1019                                         break;
1020                                 }
1021                         }
1022                         var add = new Palete.CompileError.new_from_file(f, n);
1023                         if (add.hasErrors()) {
1024                                 ls.append(add);
1025                                 return 1;
1026                         }
1027                         return 0;
1028                 }
1029                 public GLib.ListStore getErrors(string n)
1030                 {
1031                         var ls = this.errorsByType.get(n);
1032                         if (ls == null) {
1033                                 ls = new GLib.ListStore(typeof(Palete.CompileError));
1034                                 this.errorsByType.set(n, ls );
1035                         }
1036                         return ls;
1037                 }
1038                 
1039                 
1040                 public abstract Palete.LanguageClient  getLanguageServer(string lang);
1041                 
1042                 
1043                 public abstract void onSave(); // write meson?
1044                 public abstract void initDatabase();
1045                 public abstract void initialize(); // for new projects (make dirs?);
1046                 public abstract void loadJson(Json.Object obj); 
1047                 public abstract void saveJson(Json.Object obj);
1048                   
1049         }
1050 }
1051