diff --git a/src/dlangide/ui/commands.d b/src/dlangide/ui/commands.d index a2e1430..ad427d9 100644 --- a/src/dlangide/ui/commands.d +++ b/src/dlangide/ui/commands.d @@ -31,6 +31,8 @@ enum IDEActions : int { DebugPause, HelpAbout, WindowCloseAllDocuments, + CreateNewWorkspace, + AddToCurrentWorkspace, } const Action ACTION_FILE_NEW_SOURCE_FILE = new Action(IDEActions.FileNew, "MENU_FILE_NEW_SOURCE_FILE"c, "document-new", KeyCode.KEY_N, KeyFlag.Control); @@ -62,3 +64,5 @@ const Action ACTION_EDIT_UNDO = new Action(EditorActions.Undo, "MENU_EDIT_UNDO"c const Action ACTION_EDIT_REDO = new Action(EditorActions.Redo, "MENU_EDIT_REDO"c, "edit-redo"c, KeyCode.KEY_Z, KeyFlag.Control|KeyFlag.Shift); const Action ACTION_HELP_ABOUT = new Action(IDEActions.HelpAbout, "MENU_HELP_ABOUT"c); const Action ACTION_WINDOW_CLOSE_ALL_DOCUMENTS = new Action(IDEActions.WindowCloseAllDocuments, "MENU_WINDOW_CLOSE_ALL_DOCUMENTS"c); +const Action ACTION_CREATE_NEW_WORKSPACE = new Action(IDEActions.CreateNewWorkspace, "Create new workspace"d); +const Action ACTION_ADD_TO_CURRENT_WORKSPACE = new Action(IDEActions.CreateNewWorkspace, "Add to current workspace"d); diff --git a/src/dlangide/ui/frame.d b/src/dlangide/ui/frame.d index ffb855e..9bf3e09 100644 --- a/src/dlangide/ui/frame.d +++ b/src/dlangide/ui/frame.d @@ -371,6 +371,8 @@ class IDEFrame : AppFrame { dlg.onDialogResult = delegate(Dialog dlg, const Action result) { if (result.id == ACTION_OPEN.id) { string filename = result.stringParam; + if (filename.length) + openFileOrWorkspace(filename); } }; dlg.show(); @@ -382,13 +384,68 @@ class IDEFrame : AppFrame { return false; } + void openFileOrWorkspace(string filename) { + if (filename.isWorkspaceFile) { + Workspace ws = new Workspace(); + if (ws.load(filename)) { + askForUnsavedEdits(delegate() { + setWorkspace(ws); + }); + } else { + window.showMessageBox(UIString("Cannot open workspace"d), UIString("Error occured while opening workspace"d)); + return; + } + } else if (filename.isProjectFile) { + Project project = new Project(); + if (!project.load(filename)) { + window.showMessageBox(UIString("Cannot open project"d), UIString("Error occured while opening project"d)); + return; + } + string defWsFile = project.defWorkspaceFile; + if (currentWorkspace) { + Project existing = currentWorkspace.findProject(project.filename); + if (existing) { + window.showMessageBox(UIString("Open project"d), UIString("Project is already in workspace"d)); + return; + } + window.showMessageBox(UIString("Open project"d), UIString("Do you want to create new workspace or use current one?"d), + [ACTION_ADD_TO_CURRENT_WORKSPACE, ACTION_CREATE_NEW_WORKSPACE, ACTION_CANCEL], 0, delegate(const Action result) { + if (result.id == IDEActions.CreateNewWorkspace) { + // new ws + Workspace ws = new Workspace(); + ws.name = project.name; + ws.description = project.description; + ws.save(defWsFile); + setWorkspace(ws); + } else if (result.id == IDEActions.AddToCurrentWorkspace) { + // add to current + currentWorkspace.addProject(project); + currentWorkspace.save(); + _wsPanel.reloadItems(); + } + return true; + }); + } else { + // new workspace file + } + } else { + window.showMessageBox(UIString("Invalid workspace file"d), UIString("This file is not a valid workspace or project file"d)); + } + } + bool loadWorkspace(string path) { // testing workspace loader Workspace ws = new Workspace(); ws.load(path); + setWorkspace(ws); + ws.save(ws.filename ~ ".bak"); + return true; + } + + void setWorkspace(Workspace ws) { + closeAllDocuments(); currentWorkspace = ws; _wsPanel.workspace = ws; - return true; } } diff --git a/src/dlangide/ui/wspanel.d b/src/dlangide/ui/wspanel.d index 53df648..9354405 100644 --- a/src/dlangide/ui/wspanel.d +++ b/src/dlangide/ui/wspanel.d @@ -94,14 +94,13 @@ class WorkspacePanel : DockWindow { } } - @property void workspace(Workspace w) { - _workspace = w; + void reloadItems() { _tree.requestLayout(); _tree.items.clear(); - if (w) { - TreeItem root = _tree.items.newChild(w.filename, w.name, "project-development"); + if (_workspace) { + TreeItem root = _tree.items.newChild(_workspace.filename, _workspace.name, "project-development"); root.intParam = ProjectItemType.Workspace; - foreach(project; w.projects) { + foreach(project; _workspace.projects) { TreeItem p = root.newChild(project.filename, project.name, "project-open"); p.intParam = ProjectItemType.Project; addProjectItems(p, project.items); @@ -109,6 +108,11 @@ class WorkspacePanel : DockWindow { } else { _tree.items.newChild("none", "New workspace"d, "project-development"); } + } + + @property void workspace(Workspace w) { + _workspace = w; + reloadItems(); _tree.onTreeContentChange(null); } } diff --git a/src/dlangide/workspace/project.d b/src/dlangide/workspace/project.d index c170d59..c5c3ab8 100644 --- a/src/dlangide/workspace/project.d +++ b/src/dlangide/workspace/project.d @@ -9,6 +9,22 @@ import std.json; import std.utf; import std.algorithm; +/// return true if filename matches rules for workspace file names +bool isProjectFile(string filename) { + return filename.baseName.equal("dub.json") || filename.baseName.equal("package.json"); +} + +string toForwardSlashSeparator(string filename) { + char[] res; + foreach(ch; filename) { + if (ch == '\\') + res ~= '/'; + else + res ~= ch; + } + return cast(string)res; +} + /// project item class ProjectItem { protected Project _project; @@ -178,7 +194,7 @@ class WorkspaceItem { return false; } - bool save() { + bool save(string fname = null) { return false; } } @@ -211,6 +227,10 @@ class Project : WorkspaceItem { _workspace = p; } + @property string defWorkspaceFile() { + return buildNormalizedPath(_filename.dirName, toUTF8(name) ~ WORKSPACE_EXTENSION); + } + ProjectFolder findItems() { ProjectFolder folder = new ProjectFolder(_filename); folder.project = this; diff --git a/src/dlangide/workspace/workspace.d b/src/dlangide/workspace/workspace.d index 003ad7e..7067a94 100644 --- a/src/dlangide/workspace/workspace.d +++ b/src/dlangide/workspace/workspace.d @@ -6,6 +6,7 @@ import std.path; import std.file; import std.json; import std.utf; +import std.algorithm; /** Exception thrown on Workspace errors @@ -18,6 +19,12 @@ class WorkspaceException : Exception } } +immutable string WORKSPACE_EXTENSION = ".dlangidews"; + +/// return true if filename matches rules for workspace file names +bool isWorkspaceFile(string filename) { + return filename.endsWith(WORKSPACE_EXTENSION); +} /// DlangIDE workspace class Workspace : WorkspaceItem { @@ -41,6 +48,53 @@ class Workspace : WorkspaceItem { return null; } + /// find project in workspace by filename + Project findProject(string filename) { + foreach (Project p; _projects) { + if (p.filename.equal(filename)) + return p; + } + return null; + } + + void addProject(Project p) { + _projects ~= p; + p.workspace = this; + } + + string absoluteToRelativePath(string path) { + return toForwardSlashSeparator(relativePath(path, _dir)); + } + + + override bool save(string fname = null) { + if (fname.length > 0) + filename = fname; + try { + JSONValue content; + JSONValue[string] json; + json["name"] = JSONValue(toUTF8(_name)); + json["description"] = JSONValue(toUTF8(_description)); + JSONValue[string] projects; + foreach (Project p; _projects) { + string pname = toUTF8(p.name); + string ppath = absoluteToRelativePath(p.filename); + projects[pname] = JSONValue(ppath); + } + json["projects"] = projects; + content = json; + string js = content.toPrettyString; + write(_filename, js); + } catch (JSONException e) { + Log.e("Cannot parse json", e); + return false; + } catch (Exception e) { + Log.e("Cannot read workspace file", e); + return false; + } + return true; + } + override bool load(string fname = null) { if (fname.length > 0) filename = fname; @@ -61,12 +115,14 @@ class Workspace : WorkspaceItem { string path = value.str; Log.d("project: ", key, " path:", path); if (!isAbsolute(path)) - path = buildNormalizedPath(_dir, path, "dub.json"); + path = buildNormalizedPath(_dir, path); //, "dub.json" Project project = new Project(path); _projects ~= project; project.load(); } + string js = json.toPrettyString; + write(_filename, js); } catch (JSONException e) { Log.e("Cannot parse json", e); return false; diff --git a/workspaces/sample1/sample1.dlangidews b/workspaces/sample1/sample1.dlangidews index a3f0926..97320f9 100644 --- a/workspaces/sample1/sample1.dlangidews +++ b/workspaces/sample1/sample1.dlangidews @@ -1,8 +1,8 @@ { - "name": "sample1", - "description": "Sample workspace 1 for testing of DLANG IDE", - "projects": { - "sampleproject1": "./sampleproject1", - "sampleproject2": "./sampleproject2" - } -} + "description": "Sample workspace 1 for testing of DLANG IDE", + "projects": { + "sampleproject1": "sampleproject1\/dub.json", + "sampleproject2": "sampleproject2\/dub.json" + }, + "name": "sample1" +} \ No newline at end of file