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