diff --git a/dlangide.visualdproj b/dlangide.visualdproj index 4a0d3e7..c466b60 100644 --- a/dlangide.visualdproj +++ b/dlangide.visualdproj @@ -212,6 +212,7 @@ + diff --git a/dub.json b/dub.json index 598e677..6bc42b6 100644 --- a/dub.json +++ b/dub.json @@ -11,6 +11,8 @@ "stringImportPaths": ["views", "views/res", "views/res/i18n", "views/res/mdpi"], + "copyFiles-windows": ["lib/win32/FreeImage.dll", "lib/win32/SDL2.dll", "lib/win32/dcd-server.exe"], + "dependencies": { "dlangui": "~master" } diff --git a/lib/FreeImage.dll b/lib/win32/FreeImage.dll similarity index 100% rename from lib/FreeImage.dll rename to lib/win32/FreeImage.dll diff --git a/lib/SDL2.dll b/lib/win32/SDL2.dll similarity index 100% rename from lib/SDL2.dll rename to lib/win32/SDL2.dll diff --git a/lib/win32/dcd-server.exe b/lib/win32/dcd-server.exe new file mode 100644 index 0000000..1188a98 Binary files /dev/null and b/lib/win32/dcd-server.exe differ diff --git a/src/dlangide/builders/extprocess.d b/src/dlangide/builders/extprocess.d index 69b64a1..2545ea0 100644 --- a/src/dlangide/builders/extprocess.d +++ b/src/dlangide/builders/extprocess.d @@ -282,6 +282,12 @@ class ExternalProcess { this() { } + ExternalProcessState run(string program, string[]args, string dir, TextWriter stdoutTarget, TextWriter stderrTarget = null) { + char[][] arguments; + foreach(a; args) + arguments ~= a.dup; + return run(program.dup, arguments, dir.dup, stdoutTarget, stderrTarget); + } ExternalProcessState run(char[] program, char[][]args, char[] dir, TextWriter stdoutTarget, TextWriter stderrTarget = null) { Log.d("ExternalProcess.run ", program, " ", args); _state = ExternalProcessState.None; diff --git a/src/dlangide/tools/d/dcdserver.d b/src/dlangide/tools/d/dcdserver.d new file mode 100644 index 0000000..81637c2 --- /dev/null +++ b/src/dlangide/tools/d/dcdserver.d @@ -0,0 +1,89 @@ +module dlangide.tools.d.dcdserver; + +import dlangui.core.logger; +import dlangui.core.files; +import dlangide.builders.extprocess; +import dlangide.workspace.project; +import std.conv : to; + +/// encapsulates running DCD server access +class DCDServer { + private ExternalProcess dcdProcess; + private ProtectedTextStorage stdoutTarget; + private int _port; + private bool _running; + private bool _error; + + /// port to connect to DCD + @property int port() { + return _port; + } + this(int port = 9166) { + _port = port; + } + /// returns true if there was error while trying to run server last time + @property bool isError() { + return _error; + } + /// returns true if server seems running + @property bool isRunning() { + return _running; + } + /// start DCD server + bool start() { + if (dcdProcess || stdoutTarget) { + Log.e("Already started"); + return false; + } + _error = false; + _running = false; + string dcdServerExecutable = findExecutablePath("dcd-server"); + if (!dcdServerExecutable) { + Log.e("dcd-server executable is not found"); + _error = true; + return false; + } + + string[] srcPaths = dmdSourcePaths(); + string[] arguments; + arguments ~= ("-p" ~ to!string(_port)); + foreach(p; srcPaths) { + arguments ~= "-I"; + arguments ~= p; + } + Log.i("starting dcd-server: executable path is ", dcdServerExecutable, " args: ", arguments); + dcdProcess = new ExternalProcess(); + stdoutTarget = new ProtectedTextStorage(); + ExternalProcessState state = dcdProcess.run(dcdServerExecutable, arguments, null, stdoutTarget); + if (state != ExternalProcessState.Running) { + Log.e("Error while starting DCD: process state reported is ", state); + _error = true; + dcdProcess.kill(); + dcdProcess.wait(); + destroy(dcdProcess); + dcdProcess = null; + stdoutTarget = null; + return false; + } + Log.i("DCD server is started successfully"); + _running = true; + return true; + } + /// stop DCD server + bool stop() { + if (!dcdProcess) { + Log.e("Cannot stop DCD - it's not started"); + return false; + } + Log.i("Current DCD state: ", dcdProcess.poll()); + Log.i("Killing DCD server"); + ExternalProcessState state = dcdProcess.kill(); + state = dcdProcess.wait(); + Log.i("DCD state: ", state); + destroy(dcdProcess); + dcdProcess = null; + stdoutTarget = null; + _running = false; + return true; + } +} diff --git a/src/dlangide/ui/frame.d b/src/dlangide/ui/frame.d index 67f84d0..aa1b91f 100644 --- a/src/dlangide/ui/frame.d +++ b/src/dlangide/ui/frame.d @@ -21,6 +21,7 @@ import dlangide.ui.wspanel; import dlangide.ui.outputpanel; import dlangide.ui.dsourceedit; import dlangide.ui.homescreen; +import dlangide.tools.d.dcdserver; import dlangide.workspace.workspace; import dlangide.workspace.project; import dlangide.builders.builder; @@ -64,6 +65,7 @@ class IDEFrame : AppFrame { DockHost _dockHost; TabWidget _tabs; EditorTool _editorTool; + DCDServer _dcdServer; dstring frameWindowCaptionSuffix = "DLangIDE"d; @@ -72,11 +74,14 @@ class IDEFrame : AppFrame { window.mainWidget = this; window.onFilesDropped = &onFilesDropped; window.onCanClose = &onCanClose; + window.onClose = &onWindowClose; } override protected void init() { _appName = "dlangide"; _editorTool = new DEditorTool(this); + _dcdServer = new DCDServer(); + super.init(); } @@ -321,6 +326,12 @@ class IDEFrame : AppFrame { _logPanel.appendText(null, ldcPath ? ("ldc path: "d ~ toUTF32(ldcPath) ~ "\n"d) : ("ldc compiler is not found!\n"d)); _logPanel.appendText(null, gdcPath ? ("gdc path: "d ~ toUTF32(gdcPath) ~ "\n"d) : ("gdc compiler is not found!\n"d)); + if (_dcdServer.start()) { + _logPanel.appendText(null, "dcd-server is started on port "d ~ to!dstring(_dcdServer.port) ~ "\n"d); + } else { + _logPanel.appendText(null, "cannot start dcd-server: code completion for D code will not work"d); + } + _dockHost.addDockedWindow(_logPanel); return _dockHost; @@ -689,6 +700,16 @@ class IDEFrame : AppFrame { }); return false; } + /// called when main window is closing + void onWindowClose() { + Log.i("onWindowClose()"); + if (_dcdServer) { + if (_dcdServer.isRunning) + _dcdServer.stop(); + destroy(_dcdServer); + _dcdServer = null; + } + } } Widget createAboutWidget() @@ -698,8 +719,8 @@ Widget createAboutWidget() res.addChild(new TextWidget(null, "DLangIDE"d)); res.addChild(new TextWidget(null, "(C) Vadim Lopatin, 2014"d)); res.addChild(new TextWidget(null, "http://github.com/buggins/dlangide"d)); - res.addChild(new TextWidget(null, "So far, it's just a test for DLangUI library."d)); - res.addChild(new TextWidget(null, "Later I hope to make working IDE :)"d)); + res.addChild(new TextWidget(null, "IDE for D programming language written in D"d)); + res.addChild(new TextWidget(null, "Uses DlangUI library for GUI"d)); Button closeButton = new Button("close", "Close"d); closeButton.onClickListener = delegate(Widget src) { Log.i("Closing window");