fix last merge - highlight support
[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                         
496                         // used to load paths..
497                         this.sub_paths = new Gee.ArrayList<JsRender.JsRender>();
498                         this.files = new Gee.HashMap<string,JsRender.JsRender>();
499                         this.loadSubDirectories("", 0); // must happend before loadJson! (as compile groups checks if file exists.
500                          
501
502                         
503                         if (FileUtils.test(this.path + "/.roobuilder.jcfg", FileTest.EXISTS)) {
504                                   
505                                 var pa = new Json.Parser();
506                                 try { 
507                                         pa.load_from_file(this.path + "/.roobuilder.jcfg");
508                                 } catch (GLib.Error e) {
509                                         GLib.error("could not load json file %s", e.message);
510                                 }
511                                 var node = pa.get_root();
512
513                                 
514                                 if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
515                                         GLib.debug("SKIP %s/.roobuilder.jcfg  - invalid format?",this.path);
516                                         return;
517                                 }
518                                 
519                                 var obj = node.get_object ();
520                                  
521                                 this.loadJson(obj);
522                         } 
523                         this.initDatabase();    
524                         this.is_scanned = true; // loaded.. dont need to do it again..
525                          GLib.debug("load is_scanned = true");
526                         
527                 }
528                 
529                 
530                 /*
531                 
532                 public string firstPath()
533                 {
534                         var iter = this.paths.map_iterator();
535                         while (iter.next()) {
536                                 return iter.get_key();
537                         }
538                   
539                         return "";
540                 }
541
542                 public bool hasPath(string path)
543                 {
544                         var iter = this.paths.map_iterator();
545                         while (iter.next()) {
546                                 if (iter.get_key() == path) {
547                                 return true;
548                         }
549                         }
550                   
551                         return false;
552                 }
553
554                 
555                 // returns the first path
556                 public string getName()
557                 {
558                         var iter = this.paths.map_iterator();
559                         while (iter.next()) {
560                                 return GLib.Path.get_basename(iter.get_key());
561                         }
562                   
563                         return "";
564                 }
565                 */
566
567                 public Gee.ArrayList<JsRender.JsRender> sortedFiles()
568                 {
569                         var files = new Gee.ArrayList<JsRender.JsRender>();
570
571                         var fiter = this.files.map_iterator();
572                         while(fiter.next()) {
573                                 files.add(fiter.get_value());
574                         }
575                         files.sort((fa,fb) => {
576                                 return ((JsRender.JsRender)fa).name.collate(((JsRender.JsRender)fb).name);
577
578                         });
579                         return files;
580
581                 }
582                 
583          
584          
585                 public string listAllFilesToString()
586                 {
587                  
588                         var iter = this.sortedFiles().list_iterator();
589                         var ret = "ID\tName\tDirectory\n";
590                         while (iter.next()) {
591                                 ret += "%s\n".printf(
592                                                  
593                                                 iter.get().name
594                                                  
595                                                 );
596                          
597                                 
598                         }
599                         
600                         return ret;
601                 
602                 }
603                 
604          
605          
606          
607                 public JsRender.JsRender? getByRelPath(string relpath)
608                 {
609                         foreach(var f in this.files.values) {
610                                 if (f.relpath == relpath || f.relTargetName() == relpath) {
611                                         return f;
612                                 }
613                         };
614                         return null;
615                 }
616                 // this get's a file using the full path ( replaces vala->bjs if they exist);
617                 
618                 public JsRender.JsRender? getByPath(string path)
619                 {
620                  
621                         // keys are not paths...
622                         foreach(var f in this.files.values) {
623                                 //GLib.debug("check %s = %s ? %s", path, f.path, f.targetName());
624                                 if (f.path == path || f.targetName() == path) {
625                                         return f;
626                                 }
627                         };
628                         return null;                    
629                 }
630                 
631                 public JsRender.JsRender? getById(string id)
632                 {
633                         foreach(var f in this.files.values) {
634                                 if (f.id == id) {
635                                         return f;
636                                 }
637                         };
638                         return null;
639                 }
640  
641                 // name should include extension.       
642                 /*
643                 public JsRender.JsRender? newFile (string xtype, string sub_dir, string name)
644                 {
645                         try {
646                                 var fp = this.path + (sub_dir.length > 0  ? "/" : "") + sub_dir;
647                                 if (this.files.has_key(fp + "/" +  name)) {
648                                         return null;
649                                 }
650                                  
651                                 
652                                 var ret =  JsRender.JsRender.factory(xtype, 
653                                                                                          this, 
654                                                                                          fp + "/" +  name
655                                                                                          );
656                                 this.files.set(fp + "/" +  name , ret);
657                                 return ret;
658                         } catch (JsRender.Error e) {
659                                 GLib.error("failed to create file %s", e.message);
660                         }
661                 }
662                 */
663          
664                 public JsRender.JsRender loadFileOnly (string path)
665                 {
666                         var xt = this.xtype;
667                         try {
668                                 return JsRender.JsRender.factory(xt, this, path);
669                         } catch (JsRender.Error e) {
670                                 GLib.error("failed to create file %s", e.message);
671                         } 
672                         
673                 } 
674                 
675                 /* 
676                 public JsRender.JsRender create(string filename)
677                 {
678                         var ret = this.loadFileOnly(filename);
679                         ret.save();
680                         this.addFile(ret);
681                         return ret;
682                         
683                 }
684                 */
685                 private void loadSubDirectories(string subdir, int dp) 
686                 {
687                         //dp = dp || 0;
688                         //print("Project.Base: Running scandir on " + dir +"\n");
689                         if (dp > 5) { // no more than 5 deep?
690                                 return;
691                         }
692                         if (subdir == "build") { // cmake!
693                                 return;
694                         }
695                         
696                         if (subdir == "autom4te.cache") { // automake?
697                                 return;
698                         }
699                         //if (subdir == "debian") { // debian!?
700                         //      return;
701                         //}
702
703                         
704                         var dir = this.path + (subdir.length > 0 ? "/" : "") + subdir;
705                         
706                         
707                         GLib.debug("Project %s Scan Dir: %s", this.name, dir);
708                         var jsDir = new JsRender.Dir(this, dir);
709                         this.sub_paths.add(jsDir); // might be ''...
710                         
711                         
712                         // this should be done async -- but since we are getting the proto up ...
713                         var other_files = new Gee.ArrayList<string>();
714                         var bjs_files = new Gee.ArrayList<string>();
715                         var vala_files = new Gee.ArrayList<string>();
716                         var subs = new Gee.ArrayList<string>();
717                         
718                         
719                         var f = File.new_for_path(dir);
720                         try {
721                                 var file_enum = f.enumerate_children(GLib.FileAttribute.STANDARD_DISPLAY_NAME, GLib.FileQueryInfoFlags.NONE, null);
722                                 
723                                  
724                                 FileInfo next_file; 
725                                 while ((next_file = file_enum.next_file(null)) != null) {
726                                         var fn = next_file.get_display_name();
727                         
728                                          
729                                         //print("trying"  + dir + "/" + fn +"\n");
730                                         
731                                         if (fn[0] == '.') { // skip hidden
732                                                 continue;
733                                         }
734                                         
735                                         if (FileUtils.test(dir  + "/" + fn, GLib.FileTest.IS_DIR)) {
736                                                 subs.add(dir  + "/" + fn);
737                                                 continue;
738                                         }
739                                         if (Regex.match_simple("\\.(o|cache|out|stamp|~)$", fn)) { // object..
740                                                 continue;
741                                         }
742                                         if (Regex.match_simple("^(config1.builder|a.out|stamp-h1|depcomp|config.log|config.status|obj-x86_64-linux-gnu)$", fn)) { // object..
743                                                 continue;
744                                         }
745                                         
746                                         
747                                         if (Regex.match_simple("\\.vala$", fn)) {
748                                                 vala_files.add(fn);
749                                                 other_files.add(fn);
750                                                 //print("no a bjs\n");
751                                                 continue;
752                                         }
753                                         if (!Regex.match_simple("\\.bjs$", fn)) {
754                                                 other_files.add(fn);
755                                                 //print("no a bjs\n");
756                                                 continue;
757                                         }
758                                         bjs_files.add(fn.substring(0, fn.length-4));
759                                         
760                                         var xt = this.xtype;
761                                         var el = JsRender.JsRender.factory(xt,this, dir + "/" + fn);
762                                         this.files.set( dir + "/" + fn, el);
763                                         jsDir.childfiles.append(el);
764                                         
765                                         // parent ?? 
766                                         
767                                          
768                                 }
769                         } catch (Error e) {
770                                 GLib.warning("Project::scanDirs failed : " + e.message + "\n");
771                         } catch (GLib.Error e) {
772                                 GLib.warning("Project::scanDirs failed : " + e.message + "\n");
773                         } 
774
775                         foreach(var fn in other_files) {
776                                 var dpos = fn.last_index_of(".");
777                                 var without_ext = fn.substring(0, dpos);
778                                 if (bjs_files.contains(without_ext)) {  // will remove vala and c.
779                                         continue;
780                                 }
781                                 // c with a vala - skip
782                                 if (Regex.match_simple("\\.c$", fn) && vala_files.contains(without_ext + ".vala")) {
783                                         continue;
784                                 }
785                                 // Makefile (only allow am files at present.
786                                 if (without_ext == "Makefile") {
787                                         if (!Regex.match_simple("\\.am$", fn)) {
788                                                 continue;
789                                         }
790                                 }
791                                 if (without_ext == "configure") {
792                                         if (!Regex.match_simple("\\.ac$", fn)) {
793                                                 continue;
794                                         }
795                                 }
796                                 
797                                 
798                                 
799                                 
800                                 
801                                 //GLib.debug("Could have added %s/%s", dir, fn);
802                                 try {
803                                          var el = JsRender.JsRender.factory("PlainFile",this, dir + "/" + fn);
804                                          this.files.set( dir + "/" + fn, el);
805                                         jsDir.childfiles.append(el);
806                                 } catch (JsRender.Error e) {
807                                         GLib.warning("Project::scanDirs failed : " + e.message + "\n");
808                                 }
809                         }
810                         
811                         foreach (var sd in subs) {
812                                  this.loadSubDirectories(sd.substring(this.path.length+1), dp+1);
813                         }
814                         
815                 
816                 }
817                 
818                 // calle dfrom new file dialog
819                 // add files to dires (and main file list)
820                 // update 
821                         
822                  
823                 public void addFile(JsRender.JsRender pfile)
824                 { // add a single file, and trigger changed.
825                 
826                         if (pfile.xtype == "Gtk" || pfile.xtype == "Roo" ) {
827                                 this.files.set(pfile.path, pfile); // duplicate check
828                                 
829                                 if (pfile.xtype == "Gtk" && pfile.build_module != "") {
830                                 
831                                         var gfile = (JsRender.Gtk) pfile;
832                                         gfile.updateCompileGroup("", pfile.build_module);
833                                          
834                                 }
835                         }
836                         var sp = this.findDir(pfile.dir);
837                         sp.childfiles.append(pfile);    
838                         this.files.set(pfile.path, pfile);
839                         
840                         this.on_changed();
841                 }
842                 
843                 
844                 
845                 public void deleteFile(JsRender.JsRender file) 
846                 {
847                         if (file.xtype =="Dir") {
848                                 return;
849                         }
850                         var sp = this.findDir(file.dir);
851                         for(var i =0;i < sp.childfiles.n_items; i++) {
852                                 var jf = (JsRender.JsRender) sp.childfiles.get_item(i);
853                                 if (jf.path == file.path) {
854                                         sp.childfiles.remove(i);
855                                         break;
856                                 }
857                         }
858                         if (this.files.has_key(file.path)) {
859                                 this.files.unset(file.path);
860                         }
861
862                         
863                         file.remove();
864                         this.save();
865                         
866                         // remove it from 
867                         
868                         
869                 }
870                         
871                 // but do not add it to our list.!!!
872                 public void makeProjectSubdir(string name)
873                 {
874                         var dir = File.new_for_path(this.path + "/" + name);
875                         if (FileUtils.test(this.path + "/" + name, FileTest.EXISTS)) {
876                                 return;
877                         }
878                         try {
879                                  
880                                 dir.make_directory();   
881                         } catch (GLib.Error e) {
882                                 GLib.error("Failed to make directory %s", this.path + "/" + name);
883                         } 
884                 }
885                 
886                 public void createDir(string subdir)   // add a single dir, and trigger changed.
887                 {
888                         if (subdir.strip() == "" || this.subpathsContains(subdir)) {
889                                 return;
890                         }
891                         var dir= File.new_for_path(this.path + "/" + subdir);
892
893                         if (!dir.query_exists()) {
894                         
895                                 try {
896                                          
897                                         dir.make_directory();   
898                                 } catch (GLib.Error e) {
899                                         GLib.error("Failed to make directory %s", this.path + "/" + name);
900                                 }
901
902                         }
903                         this.sub_paths.add(new JsRender.Dir(this,this.path + "/" + subdir));
904                         this.on_changed();  // not sure if it's needed - adding a dir doesnt really change much.
905                 }
906                 
907                 // this store is used in the icon view ?? do we need to store and update it?
908                 public void loadFilesIntoStore(GLib.ListStore ls) 
909                 {
910                         ls.remove_all();
911                         //GLib.debug("Load files (into grid) %s", this.name);                   
912                         foreach(var f in this.files.values) {
913                         //      GLib.debug("Add file %s", f.name);
914                                 if (f.xtype == "PlainFile") {
915                                         continue;
916                                 }
917                                 ls.append(f);
918                         }
919                         
920                 }
921                 public void loadDirsIntoStore(GLib.ListStore  ls) 
922                 {
923                         ls.remove_all();
924                         foreach(var f in this.sub_paths) {
925                                 //GLib.debug("Add %s", f.name);
926                                 ls.append(f);
927                         }
928                          ;
929                 }
930                 
931                 public bool subpathsContains(string subpath) 
932                 {
933                         foreach(var sp in this.sub_paths) {
934
935                                 if (sp.path == this.path + "/" + subpath) {
936                                         return true;
937                                 }
938                         }
939                         return false;
940                         
941                 }
942                 
943                 public void loadDirsToStringList( global::Gtk.StringList sl, string prefix) 
944                 {
945                          
946                         while (sl.get_n_items() > 0) {
947                                 sl.remove(0);
948                         }
949                         
950                         foreach(var sp in this.sub_paths) {
951                                  var add = sp.path == this.path ? "/" : sp.path.substring(this.path.length);
952                                 if (prefix.length > 0 && !add.has_prefix(prefix)) {
953                                         continue;
954                                 }
955                                 sl.append(add);
956                         }
957                 
958                 }
959                 
960                 public JsRender.Dir? findDir(string path) {
961                         
962                         foreach(var jdir in this.sub_paths) { 
963                                 if (path == jdir.path) {
964                                         return (JsRender.Dir)jdir;
965                                 }
966                         }
967                         return null;
968                 }
969                 
970                 public string[] pathsMatching(string name, bool full_path)
971                 {
972                         string[] ret = {};
973                          
974                         foreach(var jdir in this.sub_paths) { 
975                                 
976
977                                 
978                                 if (Path.get_basename (jdir.path) == name) {
979                                         GLib.debug("pathsMatching %s\n", jdir.path);
980                                         ret += full_path ? jdir.path : jdir.relpath;
981                                 }
982                                 
983                         }
984                         return ret;
985                         
986                 }
987                 public Gee.ArrayList<string> readArray(Json.Array ar) 
988                 {
989                         var ret = new Gee.ArrayList<string>();
990                         for(var i =0; i< ar.get_length(); i++) {
991                                 var add = ar.get_string_element(i);
992                                 if (ret.contains(add)) {
993                                         continue;
994                                 }
995                         
996                                 ret.add(add);
997                         }
998                         return ret;
999                 }
1000                 
1001                 // called from file..
1002                 public void addError(JsRender.JsRender f, Lsp.Diagnostic diag)
1003                 {
1004                         var new_ce = new Palete.CompileError.new_from_diagnostic(f, diag);
1005                         var ls = this.getErrors(new_ce.category); // will create if necessary..
1006                         // find the file in the list store.
1007
1008                         for(var i =0; i < ls.get_n_items(); i++) {
1009                                 var ce = ls.get_item(i) as Palete.CompileError;
1010                                 if (ce.file.path == f.path) {
1011                                         ce.lines.append(new_ce);
1012                                         return;
1013                                 } 
1014                         }
1015                         // we did not have the file..
1016                         var add = new Palete.CompileError.new_from_file(f, diag.category);
1017                         ls.append(add);
1018                         add.lines.append(new_ce);
1019                           
1020                 }
1021                 public void removeError(JsRender.JsRender f, Lsp.Diagnostic diag)
1022                 {
1023                         var ls = this.getErrors(diag.category);
1024                         for(var i =0; i < ls.get_n_items(); i++) {
1025                                 var ce = ls.get_item(i) as Palete.CompileError;
1026                                 if (ce.file.path != f.path) {
1027                                         continue;
1028                                 }
1029                                 for(var j =0; j < ce.lines.get_n_items(); j++) {
1030                                         var  lce = ce.lines.get_item(j) as Palete.CompileError;
1031                                         
1032                                         if (!diag.equals( lce.diag)) {
1033                                                 continue;
1034                                         }
1035                                         ce.lines.remove(j);
1036                                         if (ce.lines.get_n_items() < 1) {
1037                                                 ls.remove(i);
1038                                                 return;
1039                                         }
1040                                 }
1041                         }
1042
1043                 }
1044                 public GLib.ListStore getErrors(string n)
1045                 {
1046                         var ls = this.errorsByType.get(n);
1047                         if (ls == null) {
1048                                 ls = new GLib.ListStore(typeof(Palete.CompileError));
1049                                 this.errorsByType.set(n, ls );
1050                         }
1051                         return ls;
1052                 }
1053                 
1054                 
1055                 public abstract Palete.LanguageClient  getLanguageServer(string lang);
1056                 
1057                 
1058                 public abstract void onSave(); // write meson?
1059                 public abstract void initDatabase();
1060                 public abstract void initialize(); // for new projects (make dirs?);
1061                 public abstract void loadJson(Json.Object obj); 
1062                 public abstract void saveJson(Json.Object obj);
1063                   
1064         }
1065 }
1066