fix line numbering issues with vala generator - hopefully fixes completion in node...
[roobuilder] / src / Project / Project.vala
index e7a098b..d10c23a 100644 (file)
@@ -7,6 +7,27 @@
  * 
  * we need to sort out that - paths is currently a key/value array..
  * 
+ * currently we store projects in ~/.Builder/{md5}.json
+   - then for Gtk projects we have a file config1.builder - which contains dependancies, and a list of files for each target
+     (for builder it's ended up in src/Builder/config1.builder? by accident.
+   - should really support something like 
+       roobuilder --build {path_to_cfg} {target} - or local directory if not set..
+       roobuilder --build-errors {path_to_cfg} {target} - or local directory if not set..
+       
+       
+   
+   
+   should really store project data in the directory of the project?
+   
+   
+   // steps:
+   // List of projects - just an array of paths in .Builder/Projects.json
+   
+   // .roobuilder.jcfg  << hidden file with project details?
+   
+   
+   
  * 
  * 
  */
@@ -19,63 +40,73 @@ namespace Project {
                INVALID_FORMAT
        }
 
+
+       
        // static array of all projects.
-       public Gee.HashMap<string,Project>  projects;
+       private Gee.ArrayList<Project>  projects;
        
        
        
        public bool  projects_loaded = false;
-
        
        
-       public class Project : Object {
+       // used to pass around callbacks with project as a return
+       public class Callback : Object {
+               public signal void call(Project project);
+       }
+       
+       public abstract class Project : Object {
                
                public signal void on_changed (); 
        
-               public string id;
-               public string fn = ""; // just a md5...
-               public string name = "";
-               public string runhtml = "";
-               public string base_template = "";
-               public string rootURL = "";
-               public string html_gen = "";
-               
-               public Gee.HashMap<string,string> paths;
-               public Gee.HashMap<string,JsRender.JsRender> files ;
+               //public string id;
+               //public string fn = ""; // just a md5...
+               public string name  { 
+                       private set {} 
+                       owned get {
+                               return GLib.Path.get_basename(path);
+                       }
+                        
+               }
+                               
+               
+               public string path = "";
+               private Gee.ArrayList<JsRender.JsRender> sub_paths;
+               
+               private Gee.HashMap<string,JsRender.JsRender> files ;  // contains full list of files.
                //tree : false,
                public  string xtype;
                
-               public Json.Object json_project_data;
-               public Palete.RooDatabase roo_database;
+               //public Json.Object json_project_data;
+
                public Palete.Palete palete;
                 
-               bool is_scanned; 
-          
+               private bool is_scanned = false; 
+               public  Gee.HashMap<string,Palete.GirObject> gir_cache = null; // used by Gir ??? is this used by Roo?
+               //public Palete.ValaCompileRequest last_request = null; // depricated?
+               public Gee.HashMap<string,GLib.ListStore>? errorsByType = null;
+               
+               
+               protected Gee.HashMap<string,Palete.LanguageClient> language_servers;
                
-               public Project (string path) {
+               protected Project (string path) {
                        
-                       this.name = GLib.Path.get_basename(path); // default..
-                       this.json_project_data = new Json.Object();
+                        
+                       //this.json_project_data = new Json.Object();
                        
                        this.is_scanned = false;
-                       this.paths = new Gee.HashMap<string,string>();
+                       this.sub_paths = new Gee.ArrayList<JsRender.JsRender>();
                        this.files = new Gee.HashMap<string,JsRender.JsRender>();
                        //XObject.extend(this, cfg);
                        //this.files = { }; 
-                       if (path.length > 0) {
-                               this.paths.set(path, "dir");
-                       }
-                       // dummy roo database...
-                       this.initRooDatabase();
-                       
+                       this.path = path;
+                       this.language_servers = new Gee.HashMap<string,Palete.LanguageClient>();
+                       this.language_servers.set("dummy", new Palete.LanguageClientDummy(this));
+                       this.errorsByType = new  Gee.HashMap<string,GLib.ListStore>();
                        
-                       
-               }
-               public void  initRooDatabase()
-               {
-                        
-                       this.roo_database = new Palete.RooDatabase.from_project(this);
                }
+                
                
                
                
@@ -87,72 +118,130 @@ namespace Project {
 
                        var dirname = GLib.Environment.get_home_dir() + "/.Builder";
                        var dir = File.new_for_path(dirname);
-                               if (!dir.query_exists()) {
-                               dir.make_directory();
+                       if (!dir.query_exists()) {
+                               try {
+                                       dir.make_directory();
+                               } catch(GLib.Error e) {
+                                       GLib.error("could not make builder directory %s", e.message);
+                               }
                                return;
                        }
-                       projects = new  Gee.HashMap<string,Project>();
+                       projects = new  Gee.ArrayList<Project>();
                          
-                  
+                   
+                   if (FileUtils.test(dirname + "/Projects.list", GLib.FileTest.IS_REGULAR)) {
+                       loadProjectList();
+                       projects_loaded = true;
+                       return;
+               }
+               convertOldProjects(); // this saves..
+               foreach(var p in projects) {
+                       p.save();
+               }
+                       projects_loaded = true;
+       }
+        
+       public static void remove(Project p) {
+               projects.remove(p);
+               saveProjectList();
+       
+       }
+       
+       public static void saveProjectList()
+       {
+                       var f = new Json.Object();
+                       foreach(var p in projects) {
+                               f.set_string_member(p.path, p.xtype);
+                       }
+                       
+                       var  generator = new Json.Generator ();
+                       var  root = new Json.Node(Json.NodeType.OBJECT);
+                       root.init_object(f);
+                       generator.set_root (root);
+                       generator.pretty = true;
+                       generator.indent = 4;
+
+                       var data = generator.to_data (null);
+                       var dirname = GLib.Environment.get_home_dir() + "/.Builder";
+               GLib.debug("Write new Project list\n %s", data);
+               //Posix.exit(0);
+               
+               try {
+                               //FileUtils.set_contents(dirname + "/" + this.fn + ".json", s, s.length);  
+                               FileUtils.set_contents(dirname + "/Projects.list", data, data.length);  
+                       } catch (GLib.Error e) {
+                               GLib.error("failed  to save file %s", e.message);
+                       }
+               
+       }
+       
+       
+       
+       public static void convertOldProjects()
+       {
+       
+                       var dirname = GLib.Environment.get_home_dir() + "/.Builder";
+                       var  dir = File.new_for_path(dirname);
                        try {
                                var file_enum = dir.enumerate_children(
                                                                GLib.FileAttribute.STANDARD_DISPLAY_NAME, 
                                        GLib.FileQueryInfoFlags.NONE, 
                                        null
                                );
-                               
                                 
                                FileInfo next_file; 
                                while ((next_file = file_enum.next_file(null)) != null) {
-                                               var fn = next_file.get_display_name();
+                                       var fn = next_file.get_display_name();
                                        if (!Regex.match_simple("\\.json$", fn)) {
                                                continue;
                                        }
-                                       factoryFromFile(dirname + "/" + fn);
+                                       Project.factoryFromFileOld(dirname + "/" + fn);
                                }       
-                       } catch(Error e) {
+                       } catch(GLib.Error e) {
                                GLib.warning("oops - something went wrong scanning the projects\n");
                        }
-                       
+                       GLib.debug("Loaded all old Projects - saving");
+                       Project.saveProjectList();
 
                }
 
                public static Gee.ArrayList<Project> allProjectsByName()
                {
-                       var ret = new Gee.ArrayList<Project>();
-                       var iter = projects.map_iterator();
-                               while (iter.next()) {
-                                       ret.add(iter.get_value());
-                               }
-                       // fixme -- sort...
-                       return ret;
+                       
+                       return projects;
                
                }
                
-               public static Project getProject(string name)
+               public static Project? getProjectByName(string name)
                {
                        
-                       var iter = projects.map_iterator();
-                       while (iter.next()) {
-                               if (iter.get_value().name == name) {
-                                       return iter.get_value();
+                       foreach (var p in projects) {
+                               if (p.name == name) {
+                                       return p;
                                }
-                               
                        }
                        
                        return null;
                
                }
+               public static Project? getProjectByPath(string path)
+               {
+                       
+                       foreach (var p in projects) {
+                               if (p.path == path) {
+                                       return p;
+                               }
+                       }
+                       
+                       return null;
                
+               }
                public static string listAllToString()
                {
-                       var all = new Gee.ArrayList<Project>();
+                       var all = projects;
 
-                       var fiter = projects.map_iterator();
-                       
-                       while(fiter.next()) {
-                               all.add(fiter.get_value());
-                       }
+                        
                        
                        all.sort((fa,fb) => {
                                return ((Project)fa).name.collate(((Project)fb).name);
@@ -162,10 +251,10 @@ namespace Project {
                        var iter = all.list_iterator();
                        var ret = "ID\tName\tDirectory\n";
                        while (iter.next()) {
-                               ret += "%s\t%s\t%s\n".printf(
-                                               iter.get().fn,
+                               ret += "%s\t%s\n".printf(
+                                                
                                                iter.get().name,
-                                               iter.get().firstPath()
+                                               iter.get().path
                                                );
                         
                                
@@ -176,30 +265,65 @@ namespace Project {
                }
                
                
+               public static void loadIntoStore(GLib.ListStore st)
+               {
+                       st.remove_all();
+                       foreach (var p in projects) {
+                               st.append(p);
+                       }
+                       
+               }
+                       
+               
                
-               public static Project getProjectByHash(string fn)
+               static void loadProjectList()
                {
+               
+                       var dirname = GLib.Environment.get_home_dir() + "/.Builder";
+                        
+                       projects = new  Gee.ArrayList<Project>();
+                         
+                   var pa = new Json.Parser();
+                       try { 
+                               pa.load_from_file(dirname + "/Projects.list");  
+                       } catch (GLib.Error e) {
+                               GLib.error("could not load json file %s", e.message);
+                       }
+                       var node = pa.get_root();
+                       if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
+                               GLib.error( dirname + "/Projects.list - invalid format?");
+                                
+                       }
+
                        
-                       var iter = projects.map_iterator();
-                       while (iter.next()) {
-                               if (iter.get_value().fn == fn) {
-                                       return iter.get_value();
+                       var obj = node.get_object ();
+                       obj.foreach_member((sobj, key, val) => {
+                               GLib.debug("read ProjectList %s: %s", key, val.get_string());
+                               // facotry adds project!
+                               try {
+                                       Project.factory(val.get_string(), key );
+                               } catch (GLib.Error e ) {
+                                       GLib.debug("error createing project %s", e.message);
                                }
-                               
-                       }
+                                
+                       });
                        
-                       return null;
                
                }
                
                // load project data from project file.
-               public static void   factoryFromFile(string jsonfile)
+               public static void   factoryFromFileOld(string jsonfile)
                {
                         
                        GLib.debug("parse %s", jsonfile);
 
                        var pa = new Json.Parser();
-                       pa.load_from_file(jsonfile);
+                       try { 
+                               pa.load_from_file(jsonfile);
+                       } catch (GLib.Error e) {
+                               GLib.error("could not load json file %s", e.message);
+                       }
                        var node = pa.get_root();
 
                        
@@ -221,163 +345,187 @@ namespace Project {
                                }
                                        
                        });
-
-                       
-                       var proj = factory(xtype, fpath);
-
-                       proj.json_project_data  = obj; // store the original object...
                        
-                       proj.fn =  Path.get_basename(jsonfile).split(".")[0];
-
-                       // might not exist?
-
-                       if (obj.has_member("runhtml")) {
-                                       proj.runhtml  = obj.get_string_member("runhtml"); 
-                       }
-                       // might not exist?
-                       if (obj.has_member("base_template")) {
-                                       proj.base_template  = obj.get_string_member("base_template"); 
-                       }
-                       // might not exist?
-                       if (obj.has_member("rootURL")) {
-                                       proj.rootURL  = obj.get_string_member("rootURL"); 
+                       if (fpath.length < 0 || !FileUtils.test(fpath,FileTest.IS_DIR)) {
+                               return;
                        }
                        
-                       if (obj.has_member("html_gen")) {
-                                       proj.html_gen  = obj.get_string_member("html_gen"); 
+                       Project proj;
+                       try {
+                               proj = factory(xtype, fpath);
+                       } catch (Error e)  {
+                               GLib.debug("Skip file - invalid file type");
+                               return;
                        }
+
+                       //proj.json_project_data  = obj; // store the original object...
                        
+                       //proj.fn =  Path.get_basename(jsonfile).split(".")[0];
+
+                       proj.loadJson(obj);
+                       // might not exist?
                        proj.name = obj.get_string_member("name");
 
-                        
-                       paths.foreach_member((sobj, key, val) => {
-                               proj.paths.set(key, "dir");
-                       });
-                       proj.initRooDatabase();
-                       
-                       GLib.debug("Add Project %s", proj.id);
-                       
-                       projects.set(proj.id,proj);
+                       // used to load paths..
+                       //proj.initSubDirectories();
                        
+                        
+                       //proj.initDatabase();
                        
+                       GLib.debug("Add Project %s", proj.name);
                        
+                       projects.add(proj);
+                        
                        
                }
                
                
-               public static Project factory(string xtype, string path)
+               public static Project factory(string xtype, string path) throws Error
                {
 
                        // check to see if it's already loaded..
 
-                        
-                       var iter = projects.map_iterator();
-                       while (iter.next()) {
-                               if (iter.get_value().hasPath( path)) {
-                                       return iter.get_value();
+                        foreach(var p in projects) {
+                                 if (p.path == path) {
+                                       return p;
                                 }
                        }
 
-
+                       
                        switch(xtype) {
                                case "Gtk":
-                                       return new Gtk(path);
+                                       var ret =  new Gtk(path);
+                                       projects.add(ret);
+                                       
+                                       return ret;
                                case "Roo":
-                                       return new Roo(path);
-                               case "Flutter":
-                                       return new Flutter(path);
+                                       var ret = new Roo(path);
+                                       projects.add(ret);
+                                
+                                       return ret;
+                               //case "Flutter":
+                               //      return new Flutter(path);
                        }
                        throw new Error.INVALID_TYPE("invalid project type");
                                
                }
                
                
-               
-                public static void  remove(Project project)
-               {
-                       // delete the file..
-                       var dirname = GLib.Environment.get_home_dir() + "/.Builder";
-                                
-                       FileUtils.unlink(dirname + "/" + project.fn + ".json");
-                       projects.unset(project.id,null);
-                       
-
-               }
-                
+        
 
                public void save()
                {
-                               // fixme..
-                       
-                       if (this.fn.length < 1) {
-                               // make the filename..
-                               //var t = new DateTime.now_local ();
-                               //TimeVal tv;
-                               //t.to_timeval(out tv);
-                               //var str = "%l:%l".printf(tv.tv_sec,tv.tv_usec);
-                               var str = this.firstPath();
-                               
-                                       this.fn = GLib.Checksum.compute_for_string(GLib.ChecksumType.MD5, str, str.length);
+                         
+                       var  s =  this.toJSON();
+                       GLib.debug("Save Project %s\n%s", this.name, s);
+                       try {
+                               //FileUtils.set_contents(dirname + "/" + this.fn + ".json", s, s.length);  
+                               FileUtils.set_contents(this.path + "/.roobuilder.jcfg", s, s.length);  
+                       } catch (GLib.Error e) {
+                               GLib.error("failed  to save file %s", e.message);
                        }
-
-                       var dirname = GLib.Environment.get_home_dir() + "/.Builder";
-                       var  s =  this.toJSON(false);
-                       FileUtils.set_contents(dirname + "/" + this.fn + ".json", s, s.length);  
-                       
+                       this.onSave();
                        
                }
 
+       
                
                
-               public string toJSON(bool show_all)
+               public string toJSON( )
                {
                        
-                       
-                       this.json_project_data.set_string_member("name", this.name);
-                       this.json_project_data.set_string_member("fn", this.fn);
-                       this.json_project_data.set_string_member("xtype", this.xtype);
-                       this.json_project_data.set_string_member("runhtml", this.runhtml);
-                       this.json_project_data.set_string_member("rootURL", this.rootURL);
-                       this.json_project_data.set_string_member("base_template", this.base_template);
-                       this.json_project_data.set_string_member("rootURL", this.rootURL);
-                       this.json_project_data.set_string_member("html_gen", this.html_gen);                    
-                       var paths = new Json.Object(); 
-
-
-                       var iter = this.paths.map_iterator();
-                       while (iter.next()) {
-                               paths.set_string_member(iter.get_key(), "path");
-                       }
-                       this.json_project_data.set_object_member("paths", paths);
-
-                       
-                       if (show_all) {
-                               var files = new Json.Array();
-                               
-                               
-                               var fiter = this.files.map_iterator();
-                               while (fiter.next()) {
-                                       files.add_string_element (fiter.get_key());
-                               }
-                               this.json_project_data.set_array_member("files", files);
-                               
-                       }
-
+                       var obj = new Json.Object();
+                       obj.set_string_member("xtype", this.xtype);
+                                               
+                       
+                       this.saveJson(obj);
                
                        var  generator = new Json.Generator ();
                        var  root = new Json.Node(Json.NodeType.OBJECT);
-                       root.init_object(this.json_project_data);
+                       root.init_object(obj);
                        generator.set_root (root);
-                       if (show_all) {
+                       //if (show_all) {
                                generator.pretty = true;
                                generator.indent = 4;
-                       }
+                       //}
 
                        return  generator.to_data (null);
                          
                          
                }
+               
+               // used to check what type a project might be..
+               // for 'new'
+               public static string peekProjectType(string fn) 
+               {
+                       var pa = new Json.Parser();
+                       try { 
+                               pa.load_from_file(fn);
+                       } catch (GLib.Error e) {
+                               GLib.debug("could not load json file %s", e.message);
+                               return "";
+                               
+                       }
+                       var node = pa.get_root();
+
+                       if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
+                               GLib.debug("SKIP %s/.roobuilder.jcfg  - invalid format?",fn);
+                               return "";
+                       }
+                       
+                       var obj = node.get_object ();
+
+                       var xtype =  obj.get_string_member("xtype");
+                       return xtype == null ? "" : xtype;
+               
+               }
+               
+               
+               // this will do a full scan - should only be done on viewing project..
+               // not initial load.. - may take time.
+               
+               public   void   load()
+               {
+                       if (this.is_scanned) {
+                               return;
+                       }
+                       GLib.debug("load is_scanned = false");
+                       
+                       if (FileUtils.test(this.path + "/.roobuilder.jcfg", FileTest.EXISTS)) {
+                                 
+                               var pa = new Json.Parser();
+                               try { 
+                                       pa.load_from_file(this.path + "/.roobuilder.jcfg");
+                               } catch (GLib.Error e) {
+                                       GLib.error("could not load json file %s", e.message);
+                               }
+                               var node = pa.get_root();
+
+                               
+                               if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
+                                       GLib.debug("SKIP %s/.roobuilder.jcfg  - invalid format?",this.path);
+                                       return;
+                               }
+                               
+                               var obj = node.get_object ();
+                                
+                               this.loadJson(obj);
+                       } 
+                       // used to load paths..
+                       this.sub_paths = new Gee.ArrayList<JsRender.JsRender>();
+                       this.files = new Gee.HashMap<string,JsRender.JsRender>();
+                       this.loadSubDirectories("", 0);
+                        
+                       this.initDatabase();
+                       this.is_scanned = true; // loaded.. dont need to do it again..
+                        GLib.debug("load is_scanned = true");
+                       
+               }
+               
+               
+               /*
+               
                public string firstPath()
                {
                        var iter = this.paths.map_iterator();
@@ -411,6 +559,7 @@ namespace Project {
                  
                        return "";
                }
+               */
 
                public Gee.ArrayList<JsRender.JsRender> sortedFiles()
                {
@@ -432,7 +581,7 @@ namespace Project {
         
                public string listAllFilesToString()
                {
-                       this.scanDirs();
+                
                        var iter = this.sortedFiles().list_iterator();
                        var ret = "ID\tName\tDirectory\n";
                        while (iter.next()) {
@@ -452,72 +601,75 @@ namespace Project {
         
         
         
-               public JsRender.JsRender? getByName(string name)
+               public JsRender.JsRender? getByRelPath(string relpath)
                {
-                       
-                       var fiter = files.map_iterator();
-                       while(fiter.next()) {
-                        
-                               var f = fiter.get_value();
-                               
-                               
-                               GLib.debug ("Project.getByName: %s ?= %s" ,f.name , name);
-                               if (f.name == name) {
+                       foreach(var f in this.files.values) {
+                               if (f.relpath == relpath || f.relTargetName() == relpath) {
                                        return f;
                                }
                        };
                        return null;
                }
+               // this get's a file using the full path ( replaces vala->bjs if they exist);
+               
                public JsRender.JsRender? getByPath(string path)
                {
-                       
-                       var fiter = files.map_iterator();
-                       while(fiter.next()) {
-                        
-                               var f = fiter.get_value();
-                               
-                               
-                               //GLib.debug ("Project.getByName: %s ?= %s" ,f.name , name);
-                               if (f.path == path) {
+                
+                       // keys are not paths...
+                       foreach(var f in this.files.values) {
+                               //GLib.debug("check %s = %s ? %s", path, f.path, f.targetName());
+                               if (f.path == path || f.targetName() == path) {
                                        return f;
                                }
                        };
-                       return null;
+                       return null;                    
                }
                
                public JsRender.JsRender? getById(string id)
                {
-                       
-                       var fiter = files.map_iterator();
-                       while(fiter.next()) {
-                        
-                               var f = fiter.get_value();
-                               
-                               
-                               //console.log(f.id + '?=' + id);
+                       foreach(var f in this.files.values) {
                                if (f.id == id) {
                                        return f;
                                }
-                               };
+                       };
                        return null;
                }
-
-               public JsRender.JsRender newFile (string name)
+               // name should include extension.       
+               /*
+               public JsRender.JsRender? newFile (string xtype, string sub_dir, string name)
                {
-                       var ret =  JsRender.JsRender.factory(this.xtype, 
+                       try {
+                               var fp = this.path + (sub_dir.length > 0  ? "/" : "") + sub_dir;
+                               if (this.files.has_key(fp + "/" +  name)) {
+                                       return null;
+                               }
+                                
+                               
+                               var ret =  JsRender.JsRender.factory(xtype, 
                                                                                         this, 
-                                                                                        this.firstPath() + "/" + name + ".bjs");
-                       this.addFile(ret);
-                       return ret;
+                                                                                        fp + "/" +  name
+                                                                                        );
+                               this.files.set(fp + "/" +  name , ret);
+                               return ret;
+                       } catch (JsRender.Error e) {
+                               GLib.error("failed to create file %s", e.message);
+                       }
                }
-               
+               */
+        
                public JsRender.JsRender loadFileOnly (string path)
                {
                        var xt = this.xtype;
-                       return JsRender.JsRender.factory(xt, this, path);
+                       try {
+                               return JsRender.JsRender.factory(xt, this, path);
+                       } catch (JsRender.Error e) {
+                               GLib.error("failed to create file %s", e.message);
+                       } 
                        
                } 
                
+               /* 
                public JsRender.JsRender create(string filename)
                {
                        var ret = this.loadFileOnly(filename);
@@ -526,68 +678,41 @@ namespace Project {
                        return ret;
                        
                }
-                       
-                        
-               public void addFile(JsRender.JsRender pfile) { // add a single file, and trigger changed.
-               
-               
-                       this.files.set(pfile.path, pfile); // duplicate check?
-                       this.on_changed();
-               }
-               
-               public void add(string path, string type)
+               */
+               private void loadSubDirectories(string subdir, int dp) 
                {
-                       this.paths.set(path,type);
-                       //Seed.print(" type is '" + type + "'");
-                       if (type == "dir") {
-                               this.scanDir(path);
-                       //    console.dump(this.files);
-                       }
-                       if (type == "file" ) {
-                       
-                               this.files.set(path,this.loadFileOnly( path ));
+                       //dp = dp || 0;
+                       //print("Project.Base: Running scandir on " + dir +"\n");
+                       if (dp > 5) { // no more than 5 deep?
+                               return;
                        }
-                       this.on_changed();
-                       
-               }
-                
-               public void  scanDirs() // cached version
-               {
-                       if (this.is_scanned) {
+                       if (subdir == "build") { // cmake!
                                return;
                        }
-                       this.scanDirsForce();
-                       //console.dump(this.files);
                        
-               }
-                
-               public void  scanDirsForce()
-               {
-                       this.is_scanned = true;  
-                       var iter = this.paths.map_iterator();
-                       while (iter.next()) {
-                               //print("path: " + iter.get_key() + " : " + iter.get_value() +"\n");
-                               if (iter.get_value() != "dir") {
-                                       continue;
-                               }
-                               this.scanDir(iter.get_key());
+                       if (subdir == "autom4te.cache") { // automake?
+                               return;
                        }
-                       //console.dump(this.files);
-                       
-               }
-                       // list files.
-               public void scanDir(string dir, int dp =0 ) 
-               {
-                       //dp = dp || 0;
-                       //print("Project.Base: Running scandir on " + dir +"\n");
-                       if (dp > 5) { // no more than 5 deep?
+                       if (subdir == "debian") { // debian!?
                                return;
                        }
+
+                       
+                       var dir = this.path + (subdir.length > 0 ? "/" : "") + subdir;
+                       
+                       
+                       GLib.debug("Project %s Scan Dir: %s", this.name, dir);
+                       var jsDir = new JsRender.Dir(this, dir);
+                       this.sub_paths.add(jsDir); // might be ''...
+                       
+                       
                        // this should be done async -- but since we are getting the proto up ...
                        var other_files = new Gee.ArrayList<string>();
                        var bjs_files = new Gee.ArrayList<string>();
+                       var vala_files = new Gee.ArrayList<string>();
+                       var subs = new Gee.ArrayList<string>();
+                       
                        
-                       var subs = new GLib.List<string>();;            
                        var f = File.new_for_path(dir);
                        try {
                                var file_enum = f.enumerate_children(GLib.FileAttribute.STANDARD_DISPLAY_NAME, GLib.FileQueryInfoFlags.NONE, null);
@@ -605,10 +730,23 @@ namespace Project {
                                        }
                                        
                                        if (FileUtils.test(dir  + "/" + fn, GLib.FileTest.IS_DIR)) {
-                                               subs.append(dir  + "/" + fn);
+                                               subs.add(dir  + "/" + fn);
+                                               continue;
+                                       }
+                                       if (Regex.match_simple("\\.(o|cache|gif|jpg|png|gif|out|stamp|~)$", fn)) { // object..
                                                continue;
                                        }
+                                       if (Regex.match_simple("^(config1.builder|a.out|stamp-h1|depcomp|config.log|config.status)$", fn)) { // object..
+                                               continue;
+                                       }
+                                       
                                        
+                                       if (Regex.match_simple("\\.vala$", fn)) {
+                                               vala_files.add(fn);
+                                               other_files.add(fn);
+                                               //print("no a bjs\n");
+                                               continue;
+                                       }
                                        if (!Regex.match_simple("\\.bjs$", fn)) {
                                                other_files.add(fn);
                                                //print("no a bjs\n");
@@ -619,6 +757,8 @@ namespace Project {
                                        var xt = this.xtype;
                                        var el = JsRender.JsRender.factory(xt,this, dir + "/" + fn);
                                        this.files.set( dir + "/" + fn, el);
+                                       jsDir.childfiles.append(el);
+                                       
                                        // parent ?? 
                                        
                                         
@@ -627,36 +767,281 @@ namespace Project {
                                GLib.warning("Project::scanDirs failed : " + e.message + "\n");
                        } catch (GLib.Error e) {
                                GLib.warning("Project::scanDirs failed : " + e.message + "\n");
-                       }
+                       } 
+
                        foreach(var fn in other_files) {
                                var dpos = fn.last_index_of(".");
                                var without_ext = fn.substring(0, dpos);
-                               if (bjs_files.contains(without_ext)) {
+                               if (bjs_files.contains(without_ext)) {  // will remove vala and c.
+                                       continue;
+                               }
+                               // c with a vala - skip
+                               if (Regex.match_simple("\\.c$", fn) && vala_files.contains(without_ext + ".vala")) {
                                        continue;
                                }
-                               GLib.debug("Could have added %s/%s", dir, fn);
-                               //var el = JsRender.JsRender.factory("plain",this, dir + "/" + fn);
-                               //this.files.set( dir + "/" + fn, el);
+                               // Makefile (only allow am files at present.
+                               if (without_ext == "Makefile") {
+                                       if (!Regex.match_simple("\\.am$", fn)) {
+                                               continue;
+                                       }
+                               }
+                               if (without_ext == "configure") {
+                                       if (!Regex.match_simple("\\.ac$", fn)) {
+                                               continue;
+                                       }
+                               }
+                               
+                               
+                               
+                               
+                               
+                               //GLib.debug("Could have added %s/%s", dir, fn);
+                               try {
+                                        var el = JsRender.JsRender.factory("PlainFile",this, dir + "/" + fn);
+                                        this.files.set( dir + "/" + fn, el);
+                                       jsDir.childfiles.append(el);
+                               } catch (JsRender.Error e) {
+                                       GLib.warning("Project::scanDirs failed : " + e.message + "\n");
+                               }
                        }
                        
-                       for (var i = 0; i < subs.length(); i++) {
-                                this.scanDir(subs.nth_data(i), dp+1);
+                       foreach (var sd in subs) {
+                                this.loadSubDirectories(sd.substring(this.path.length+1), dp+1);
                        }
                        
+               
                }
-               // wrapper around the javascript data...
-               public string get_string_member(string key) {
+               
+               // calle dfrom new file dialog
+               // add files to dires (and main file list)
+               // update 
                        
-                       if (!this.json_project_data.has_member(key)) {
-                               return "";
+                
+               public void addFile(JsRender.JsRender pfile)
+               { // add a single file, and trigger changed.
+               
+                       if (pfile.xtype == "Gtk" || pfile.xtype == "Roo" ) {
+                               this.files.set(pfile.path, pfile); // duplicate check
+                               
+                               if (pfile.xtype == "Gtk" && pfile.build_module != "") {
+                               
+                                       var gfile = (JsRender.Gtk) pfile;
+                                       gfile.updateCompileGroup("", pfile.build_module);
+                                        
+                               }
                        }
-                       var  ret = this.json_project_data.get_string_member(key);
-                       if (ret == null) {
-                               return "";
+                       var sp = this.findDir(pfile.dir);
+                       sp.childfiles.append(pfile);    
+                       this.files.set(pfile.path, pfile);
+                       
+                       this.on_changed();
+               }
+               
+               
+               
+               public void deleteFile(JsRender.JsRender file) 
+               {
+                       if (file.xtype =="Dir") {
+                               return;
+                       }
+                       var sp = this.findDir(file.dir);
+                       for(var i =0;i < sp.childfiles.n_items; i++) {
+                               var jf = (JsRender.JsRender) sp.childfiles.get_item(i);
+                               if (jf.path == file.path) {
+                                       sp.childfiles.remove(i);
+                                       break;
+                               }
+                       }
+                       if (this.files.has_key(file.path)) {
+                               this.files.unset(file.path);
+                       }
+
+                       
+                       file.remove();
+                       // remove it from 
+                       
+                       
+               }
+                       
+               // but do not add it to our list.!!!
+               public void makeProjectSubdir(string name)
+               {
+                       var dir = File.new_for_path(this.path + "/" + name);
+                       if (FileUtils.test(this.path + "/" + name, FileTest.EXISTS)) {
+                               return;
+                       }
+                       try {
+                                
+                               dir.make_directory();   
+                       } catch (GLib.Error e) {
+                               GLib.error("Failed to make directory %s", this.path + "/" + name);
+                       } 
+               }
+               
+               public void createDir(string subdir)   // add a single dir, and trigger changed.
+               {
+                       if (subdir.strip() == "" || this.subpathsContains(subdir)) {
+                               return;
+                       }
+                       var dir= File.new_for_path(this.path + "/" + subdir);
+
+                       if (!dir.query_exists()) {
+                       
+                               try {
+                                        
+                                       dir.make_directory();   
+                               } catch (GLib.Error e) {
+                                       GLib.error("Failed to make directory %s", this.path + "/" + name);
+                               }
+
+                       }
+                       this.sub_paths.add(new JsRender.Dir(this,this.path + "/" + subdir));
+                       this.on_changed();  // not sure if it's needed - adding a dir doesnt really change much.
+               }
+               
+               // this store is used in the icon view ?? do we need to store and update it?
+               public void loadFilesIntoStore(GLib.ListStore ls) 
+               {
+                       ls.remove_all();
+                       //GLib.debug("Load files (into grid) %s", this.name);                   
+                       foreach(var f in this.files.values) {
+                       //      GLib.debug("Add file %s", f.name);
+                               if (f.xtype == "PlainFile") {
+                                       continue;
+                               }
+                               ls.append(f);
+                       }
+                       
+               }
+               public void loadDirsIntoStore(GLib.ListStore  ls) 
+               {
+                       ls.remove_all();
+                       foreach(var f in this.sub_paths) {
+                               //GLib.debug("Add %s", f.name);
+                               ls.append(f);
+                       }
+                        ;
+               }
+               
+               public bool subpathsContains(string subpath) 
+               {
+                       foreach(var sp in this.sub_paths) {
+
+                               if (sp.path == this.path + "/" + subpath) {
+                                       return true;
+                               }
+                       }
+                       return false;
+                       
+               }
+               
+               public void loadDirsToStringList( global::Gtk.StringList sl, string prefix) 
+               {
+                        
+                       while (sl.get_n_items() > 0) {
+                               sl.remove(0);
+                       }
+                       
+                       foreach(var sp in this.sub_paths) {
+                                var add = sp.path == this.path ? "/" : sp.path.substring(this.path.length);
+                               if (prefix.length > 0 && !add.has_prefix(prefix)) {
+                                       continue;
+                               }
+                               sl.append(add);
+                       }
+               
+               }
+               
+               public JsRender.Dir? findDir(string path) {
+                       
+                       foreach(var jdir in this.sub_paths) { 
+                               if (path == jdir.path) {
+                                       return (JsRender.Dir)jdir;
+                               }
+                       }
+                       return null;
+               }
+               
+               public string[] pathsMatching(string name, bool full_path)
+               {
+                       string[] ret = {};
+                        
+                       foreach(var jdir in this.sub_paths) { 
+                               
+
+                               
+                               if (Path.get_basename (jdir.path) == name) {
+                                       GLib.debug("pathsMatching %s\n", jdir.path);
+                                       ret += full_path ? jdir.path : jdir.relpath;
+                               }
+                               
                        }
                        return ret;
                        
                }
+               public Gee.ArrayList<string> readArray(Json.Array ar) 
+               {
+                       var ret = new Gee.ArrayList<string>();
+                       for(var i =0; i< ar.get_length(); i++) {
+                               var add = ar.get_string_element(i);
+                               if (ret.contains(add)) {
+                                       continue;
+                               }
+                       
+                               ret.add(add);
+                       }
+                       return ret;
+               }
+               
+               public void updateErrorsforFile(JsRender.JsRender f) 
+               {
+                       var n = this.updateErrorsByType(f, "WARN");
+                       n += this.updateErrorsByType(f, "ERR");
+                       n += this.updateErrorsByType(f, "DEPR");
+                       
+                       if (n > 0) {
+                               BuilderApplication.updateCompileResults();
+                       }
+                       
+               }
+               public int  updateErrorsByType(JsRender.JsRender f, string n) 
+               {
+                       var ls = this.getErrors(n);
+                       
+                       // remove thie file from the list.      
+                       for(var i =0; i < ls.get_n_items(); i++) {
+                               var ce = ls.get_item(i) as Palete.CompileError;
+                               if (ce.file.path == f.path) {
+                                       ls.remove(i);
+                                       break;
+                               }
+                       }
+                       var add = new Palete.CompileError.new_from_file(f, n);
+                       if (add.hasErrors()) {
+                               ls.append(add);
+                               return 1;
+                       }
+                       return 0;
+               }
+               public GLib.ListStore getErrors(string n)
+               {
+                       var ls = this.errorsByType.get(n);
+                       if (ls == null) {
+                               ls = new GLib.ListStore(typeof(Palete.CompileError));
+                               this.errorsByType.set(n, ls );
+                       }
+                       return ls;
+               }
+               
+               
+               public abstract Palete.LanguageClient  getLanguageServer(string lang);
+               
+               
+               public abstract void onSave(); // write meson?
+               public abstract void initDatabase();
+               public abstract void initialize(); // for new projects (make dirs?);
+               public abstract void loadJson(Json.Object obj); 
+               public abstract void saveJson(Json.Object obj);
                  
        }
 }