1 module dlangide.workspace.project; 2 3 import dlangide.workspace.workspace; 4 import dlangui.core.logger; 5 import dlangui.core.collections; 6 import std.path; 7 import std.file; 8 import std.json; 9 import std.utf; 10 11 /// project item 12 class ProjectItem { 13 protected Project _project; 14 protected ProjectItem _parent; 15 protected string _filename; 16 protected dstring _name; 17 18 this(string filename) { 19 _filename = buildNormalizedPath(filename); 20 _name = toUTF32(baseName(_filename)); 21 } 22 23 this() { 24 } 25 26 @property ProjectItem parent() { 27 return _parent; 28 } 29 30 @property Project project() { 31 return _project; 32 } 33 34 @property void project(Project p) { 35 _project = p; 36 } 37 38 @property string filename() { 39 return _filename; 40 } 41 42 @property dstring name() { 43 return _name; 44 } 45 46 /// returns true if item is folder 47 @property bool isFolder() { 48 return false; 49 } 50 /// returns child object count 51 @property int childCount() { 52 return 0; 53 } 54 /// returns child item by index 55 ProjectItem child(int index) { 56 return null; 57 } 58 } 59 60 /// Project folder 61 class ProjectFolder : ProjectItem { 62 protected ObjectList!ProjectItem _children; 63 64 this(string filename) { 65 super(filename); 66 } 67 68 @property override bool isFolder() { 69 return true; 70 } 71 @property override int childCount() { 72 return _children.count; 73 } 74 /// returns child item by index 75 override ProjectItem child(int index) { 76 return _children[index]; 77 } 78 void addChild(ProjectItem item) { 79 _children.add(item); 80 item._parent = this; 81 item._project = _project; 82 } 83 bool loadDir(string path) { 84 string src = relativeToAbsolutePath(path); 85 if (exists(src) && isDir(src)) { 86 ProjectFolder dir = new ProjectFolder(src); 87 addChild(dir); 88 Log.d(" added project folder ", src); 89 dir.loadItems(); 90 return true; 91 } 92 return false; 93 } 94 bool loadFile(string path) { 95 string src = relativeToAbsolutePath(path); 96 if (exists(src) && isFile(src)) { 97 ProjectSourceFile f = new ProjectSourceFile(src); 98 addChild(f); 99 Log.d(" added project file ", src); 100 return true; 101 } 102 return false; 103 } 104 void loadItems() { 105 foreach(e; dirEntries(_filename, SpanMode.shallow)) { 106 string fn = baseName(e.name); 107 if (e.isDir) { 108 loadDir(fn); 109 } else if (e.isFile) { 110 loadFile(fn); 111 } 112 } 113 } 114 string relativeToAbsolutePath(string path) { 115 if (isAbsolute(path)) 116 return path; 117 return buildNormalizedPath(_filename, path); 118 } 119 } 120 121 /// Project source file 122 class ProjectSourceFile : ProjectItem { 123 this(string filename) { 124 super(filename); 125 } 126 } 127 128 class WorkspaceItem { 129 protected string _filename; 130 protected string _dir; 131 protected dstring _name; 132 protected dstring _description; 133 134 this(string fname = null) { 135 filename = fname; 136 } 137 138 /// file name of workspace item 139 @property string filename() { 140 return _filename; 141 } 142 143 /// file name of workspace item 144 @property void filename(string fname) { 145 if (fname.length > 0) { 146 _filename = buildNormalizedPath(fname); 147 _dir = dirName(filename); 148 } else { 149 _filename = null; 150 _dir = null; 151 } 152 } 153 154 /// name 155 @property dstring name() { 156 return _name; 157 } 158 159 /// name 160 @property void name(dstring s) { 161 _name = s; 162 } 163 164 /// name 165 @property dstring description() { 166 return _description; 167 } 168 169 /// name 170 @property void description(dstring s) { 171 _description = s; 172 } 173 174 /// load 175 bool load(string fname) { 176 // override it 177 return false; 178 } 179 180 bool save() { 181 return false; 182 } 183 } 184 185 /// DLANGIDE D project 186 class Project : WorkspaceItem { 187 protected Workspace _workspace; 188 protected bool _opened; 189 protected ProjectFolder _items; 190 this(string fname = null) { 191 super(fname); 192 _items = new ProjectFolder(fname); 193 } 194 195 string relativeToAbsolutePath(string path) { 196 if (isAbsolute(path)) 197 return path; 198 return buildNormalizedPath(_dir, path); 199 } 200 201 @property ProjectFolder items() { 202 return _items; 203 } 204 205 @property Workspace workspace() { 206 return _workspace; 207 } 208 209 @property void workspace(Workspace p) { 210 _workspace = p; 211 } 212 213 ProjectFolder findItems() { 214 ProjectFolder folder = new ProjectFolder(_filename); 215 folder.project = this; 216 folder.loadDir(relativeToAbsolutePath("src")); 217 folder.loadDir(relativeToAbsolutePath("source")); 218 return folder; 219 } 220 221 override bool load(string fname = null) { 222 if (fname.length > 0) 223 filename = fname; 224 if (!exists(filename) || !isFile(filename)) { 225 return false; 226 } 227 Log.d("Reading project from file ", _filename); 228 229 try { 230 string jsonSource = readText!string(_filename); 231 JSONValue json = parseJSON(jsonSource); 232 _name = toUTF32(json["name"].str); 233 _description = toUTF32(json["description"].str); 234 Log.d(" project name: ", _name); 235 Log.d(" project description: ", _description); 236 237 _items = findItems(); 238 } catch (JSONException e) { 239 Log.e("Cannot parse json", e); 240 return false; 241 } catch (Exception e) { 242 Log.e("Cannot read project file", e); 243 return false; 244 } 245 return true; 246 } 247 } 248