1 module dlangide.workspace.workspace;
2 
3 import dlangide.workspace.project;
4 import dlangui.core.logger;
5 import std.path;
6 import std.file;
7 import std.json;
8 import std.utf;
9 import std.algorithm;
10 
11 enum BuildOperation {
12     Build,
13     Clean,
14     Rebuild,
15     Run,
16     Upgrade
17 }
18 
19 enum BuildConfiguration {
20     Debug,
21     Release,
22     Unittest
23 }
24 
25 
26 /**
27     Exception thrown on Workspace errors
28 */
29 class WorkspaceException : Exception
30 {
31     this(string msg, string file = __FILE__, size_t line = __LINE__)
32     {
33         super(msg, file, line);
34     }
35 }
36 
37 immutable string WORKSPACE_EXTENSION = ".dlangidews";
38 
39 /// return true if filename matches rules for workspace file names
40 bool isWorkspaceFile(string filename) {
41     return filename.endsWith(WORKSPACE_EXTENSION);
42 }
43 
44 /// DlangIDE workspace
45 class Workspace : WorkspaceItem {
46     protected Project[] _projects;
47 
48     protected BuildConfiguration _buildConfiguration;
49 
50     this(string fname = null) {
51         super(fname);
52     }
53 
54     @property Project[] projects() {
55         return _projects;
56     }
57 
58     @property BuildConfiguration buildConfiguration() { return _buildConfiguration; }
59     @property void buildConfiguration(BuildConfiguration config) { _buildConfiguration = config; }
60 
61     protected Project _startupProject;
62 
63     @property Project startupProject() { return _startupProject; }
64     @property void startupProject(Project project) { _startupProject = project; }
65 
66     protected void fillStartupProject() {
67         if (!_startupProject && _projects.length)
68             _startupProject = _projects[0];
69     }
70 
71     /// tries to find source file in one of projects, returns found project source file item, or null if not found
72     ProjectSourceFile findSourceFileItem(string filename) {
73         foreach (Project p; _projects) {
74             ProjectSourceFile res = p.findSourceFileItem(filename);
75             if (res)
76                 return res;
77         }
78         return null;
79     }
80 
81     /// find project in workspace by filename
82     Project findProject(string filename) {
83         foreach (Project p; _projects) {
84             if (p.filename.equal(filename))
85                 return p;
86         }
87         return null;
88     }
89 
90     void addProject(Project p) {
91         _projects ~= p;
92         p.workspace = this;
93         fillStartupProject();
94     }
95 
96     string absoluteToRelativePath(string path) {
97         return toForwardSlashSeparator(relativePath(path, _dir));
98     }
99 
100 
101     override bool save(string fname = null) {
102         if (fname.length > 0)
103             filename = fname;
104         try {
105             JSONValue content;
106             JSONValue[string] json;
107             json["name"] = JSONValue(toUTF8(_name));
108             json["description"] = JSONValue(toUTF8(_description));
109             JSONValue[string] projects;
110             foreach (Project p; _projects) {
111                 string pname = toUTF8(p.name);
112                 string ppath = absoluteToRelativePath(p.filename);
113                 projects[pname] = JSONValue(ppath);
114             }
115             json["projects"] = projects;
116             content = json;
117             string js = content.toPrettyString;
118             write(_filename, js);
119         } catch (JSONException e) {
120             Log.e("Cannot parse json", e);
121             return false;
122         } catch (Exception e) {
123             Log.e("Cannot read workspace file", e);
124             return false;
125         }
126         return true;
127     }
128 
129     override bool load(string fname = null) {
130         if (fname.length > 0)
131             filename = fname;
132         if (!exists(_filename) || !isFile(_filename))  {
133             return false;
134         }
135         Log.d("Reading workspace from file ", _filename);
136 
137         try {
138             string jsonSource = readText!string(_filename);
139             JSONValue json = parseJSON(jsonSource);
140             _name = toUTF32(json["name"].str);
141             _description = toUTF32(json["description"].str);
142             Log.d("workspace name: ", _name);
143             Log.d("workspace description: ", _description);
144             JSONValue projects = json["projects"];
145             foreach(string key, ref JSONValue value; projects) {
146                 string path = value.str;
147                 Log.d("project: ", key, " path:", path);
148                 if (!isAbsolute(path))
149                     path = buildNormalizedPath(_dir, path); //, "dub.json"
150                 Project project = new Project(path);
151                 _projects ~= project;
152                 project.load();
153 
154             }
155             string js = json.toPrettyString;
156             write(_filename, js);
157         } catch (JSONException e) {
158             Log.e("Cannot parse json", e);
159             return false;
160         } catch (Exception e) {
161             Log.e("Cannot read workspace file", e);
162             return false;
163         }
164         fillStartupProject();
165         return true;
166     }
167     void close() {
168     }
169 }
170 
171 /// global workspace
172 __gshared Workspace currentWorkspace;