integrated dcd via dub without client/server

This commit is contained in:
Keywan Ghadami 2016-01-01 15:13:16 +01:00
parent f226563981
commit 63ff1a3a25
10 changed files with 60 additions and 255 deletions

View File

@ -199,7 +199,6 @@
<Compile Include="src\dlangide\builders\extprocess.d" />
<Compile Include="src\dlangide\tools\editortool.d" />
<Compile Include="src\dlangide\tools\d\dcdinterface.d" />
<Compile Include="src\dlangide\tools\d\dcdserver.d" />
<Compile Include="src\dlangide\tools\d\deditortool.d" />
<Compile Include="src\dlangide\tools\d\dparser.d" />
<Compile Include="src\dlangide\tools\d\dsyntax.d" />
@ -231,4 +230,4 @@
<ItemGroup>
<Folder Include="src\ddebug\gdb\" />
</ItemGroup>
</Project>
</Project>

View File

@ -126,7 +126,6 @@
<Compile Include="src\dlangide\ui\wspanel.d" />
<Compile Include="src\dlangide\tools\editortool.d" />
<Compile Include="src\dlangide\tools\d\dcdinterface.d" />
<Compile Include="src\dlangide\tools\d\dcdserver.d" />
<Compile Include="src\dlangide\tools\d\deditortool.d" />
<Compile Include="src\dlangide\tools\d\dparser.d" />
<Compile Include="src\dlangide\tools\d\dsyntax.d" />
@ -148,4 +147,4 @@
<Compile Include="src\ddc\lexer\textsource.d" />
<Compile Include="src\ddc\lexer\tokenizer.d" />
</ItemGroup>
</Project>
</Project>

View File

@ -444,7 +444,6 @@
<Folder name="tools">
<Folder name="d">
<File path="src\dlangide\tools\d\dcdinterface.d" />
<File path="src\dlangide\tools\d\dcdserver.d" />
<File path="src\dlangide\tools\d\deditortool.d" />
<File path="src\dlangide\tools\d\dparser.d" />
<File path="src\dlangide\tools\d\dsyntax.d" />

View File

@ -11,11 +11,9 @@
"stringImportPaths": ["views", "views/res", "views/res/i18n", "views/res/mdpi", "views/res/hdpi"],
"copyFiles-windows": ["lib/win32/dcd-server.exe", "lib/win32/dcd-client.exe"],
"dependencies": {
"dlangui": "~>0.7.30",
"libdparse": "==0.2.0"
"dlangui": "~>0.7.31",
"dcd": "~>0.7.4"
},
"versions": ["EmbedStandardResources"],

Binary file not shown.

Binary file not shown.

View File

@ -3,36 +3,26 @@ module dlangide.tools.d.dcdinterface;
import dlangui.core.logger;
import dlangui.core.files;
import dlangide.builders.extprocess;
import std.typecons;
import std.conv;
import std.string;
const DCD_SERVER_PORT_FOR_DLANGIDE = 9167;
const DCD_DEFAULT_PORT = 9166;
enum DCDResult : int {
DCD_NOT_RUNNING = 0,
SUCCESS,
NO_RESULT,
FAIL,
}
alias FindDeclarationResultSet = Tuple!(DCDResult, "result", string, "fileName", ulong, "offset");
alias ResultSet = Tuple!(DCDResult, "result", dstring[], "output");
//Interface to DCD
//TODO: Check if server is running, start server if needed etc.
class DCDInterface {
import server.autocomplete;
import common.messages;
private int _port;
//ExternalProcess dcdProcess;
//ProtectedTextStorage stdoutTarget;
this(int port = DCD_SERVER_PORT_FOR_DLANGIDE) {
_port = port;
//dcdProcess = new ExternalProcess();
//stdoutTarget = new ProtectedTextStorage();
}
import dsymbol.modulecache;
protected string dumpContext(string content, int pos) {
if (pos >= 0 && pos <= content.length) {
@ -47,137 +37,59 @@ class DCDInterface {
return "";
}
protected dstring[] invokeDcd(string[] arguments, string content, out bool success) {
success = false;
ExternalProcess dcdProcess = new ExternalProcess();
ProtectedTextStorage stdoutTarget = new ProtectedTextStorage();
version(Windows) {
string dcd_client_name = "dcd-client.exe";
string dcd_client_dir = null;
} else {
string dcd_client_name = "dcd-client";
string dcd_client_dir = "/usr/bin";
}
dcdProcess.run(dcd_client_name, arguments, dcd_client_dir, stdoutTarget);
dcdProcess.write(content);
dcdProcess.wait();
dstring[] output = stdoutTarget.readText.splitLines();
if(dcdProcess.poll() == ExternalProcessState.Stopped) {
success = true;
}
return output;
}
ResultSet goToDefinition(in string[] importPaths, in string filename, in string content, int index) {
ResultSet result;
FindDeclarationResultSet goToDefinition(in string[] importPaths, in string filename, in string content, int index, ref ModuleCache moduleCache) {
version(USE_LIBDPARSE) {
import dlangide.tools.d.dparser;
DParsingService.instance.addImportPaths(importPaths);
DParsedModule m = DParsingService.instance.findDeclaration(cast(ubyte[])content, filename, index);
}
debug(DCD) Log.d("DCD Context: ", dumpContext(content, index));
AutocompleteRequest request;
request.sourceCode = cast(ubyte[])content;
request.fileName = filename;
request.cursorPosition = index;
string[] arguments = ["-l", "-c"];
arguments ~= [to!string(index)];
AutocompleteResponse response = findDeclaration(request,moduleCache);
FindDeclarationResultSet result;
result.fileName = response.symbolFilePath;
result.offset = response.symbolLocation;
result.result = DCDResult.SUCCESS;
foreach(p; importPaths) {
arguments ~= "-I" ~ p;
}
if (_port != DCD_DEFAULT_PORT)
arguments ~= "-p" ~ to!string(_port);
debug(DCD) Log.d("DCD fileName:\n", result.fileName);
bool success = false;
dstring[] output = invokeDcd(arguments, content, success);
if (success) {
result.result = DCDResult.SUCCESS;
} else {
result.result = DCDResult.FAIL;
return result;
}
debug(DCD) Log.d("DCD output:\n", output);
if(output.length > 0) {
dstring firstLine = output[0];
if(firstLine.startsWith("Not Found") || firstLine.startsWith("Not found")) {
result.result = DCDResult.NO_RESULT;
return result;
}
auto split = firstLine.indexOf("\t");
if(split == -1) {
Log.d("DCD output format error.");
result.result = DCDResult.FAIL;
return result;
}
result.output ~= output[0][0 .. split];
result.output ~= output[0][split+1 .. $];
} else {
if (result.fileName is null) {
result.result = DCDResult.NO_RESULT;
//result.result = DCDResult.FAIL;
}
return result;
}
ResultSet getCompletions(in string[] importPaths, in string filename, in string content, int index) {
ResultSet getCompletions(in string[] importPaths, in string filename, in string content, int index, ref ModuleCache moduleCache) {
debug(DCD) Log.d("DCD Context: ", dumpContext(content, index));
ResultSet result;
string[] arguments = ["-c"];
arguments ~= [to!string(index)];
foreach(p; importPaths) {
arguments ~= "-I" ~ p;
}
if (_port != DCD_DEFAULT_PORT)
arguments ~= "-p" ~ to!string(_port);
bool success = false;
dstring[] output = invokeDcd(arguments, content, success);
if (success) {
result.result = DCDResult.SUCCESS;
} else {
result.result = DCDResult.FAIL;
return result;
}
debug(DCD) Log.d("DCD output:\n", output);
if (output.length == 0) {
AutocompleteRequest request;
request.sourceCode = cast(ubyte[])content;
request.fileName = filename;
request.cursorPosition = index;
AutocompleteResponse response = complete(request,moduleCache);
if(response.completions is null || response.completions.length == 0){
result.result = DCDResult.NO_RESULT;
return result;
}
enum State : int {None = 0, Identifiers, Calltips}
State state = State.None;
foreach(dstring outputLine ; output) {
if(outputLine == "identifiers") {
state = State.Identifiers;
}
else if(outputLine == "calltips") {
state = State.Calltips;
}
else {
auto split = outputLine.indexOf("\t");
if(split < 0) {
break;
}
if(state == State.Identifiers) {
result.output ~= outputLine[0 .. split];
}
}
result.result = DCDResult.SUCCESS;
result.output.length = response.completions.length;
int i=0;
foreach(s;response.completions){
result.output[i++]=to!dstring(s);
}
debug(DCD) Log.d("DCD output:\n", response.completions);
return result;
}
}

View File

@ -1,91 +0,0 @@
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;
import dlangide.tools.d.dcdinterface;
/// 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 = DCD_SERVER_PORT_FOR_DLANGIDE) {
_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;
foreach(p; srcPaths)
arguments ~= "-I" ~ p;
if (_port != DCD_DEFAULT_PORT)
arguments ~= "-p" ~ to!string(_port);
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 server - it's not started");
return false;
}
debug(DCD) Log.i("Current DCD server state: ", dcdProcess.poll());
Log.i("Stopping DCD server");
ExternalProcessState state = dcdProcess.kill();
state = dcdProcess.wait();
debug(DCD) Log.i("DCD server state: ", state);
destroy(dcdProcess);
dcdProcess = null;
stdoutTarget = null;
_running = false;
return true;
}
}

View File

@ -20,41 +20,38 @@ class DEditorTool : EditorTool
this(IDEFrame frame) {
_dcd = new DCDInterface(DCD_SERVER_PORT_FOR_DLANGIDE);
_dcd = new DCDInterface();
super(frame);
}
override bool goToDefinition(DSourceEdit editor, TextPosition caretPosition) {
string[] importPaths = editor.importPaths();
_frame.moduleCache.addImportPaths(importPaths);
string content = toUTF8(editor.text);
auto byteOffset = caretPositionToByteOffset(content, caretPosition);
ResultSet output = _dcd.goToDefinition(importPaths, editor.filename, content, byteOffset);
FindDeclarationResultSet output = _dcd.goToDefinition(importPaths, editor.filename, content, byteOffset, _frame.moduleCache);
switch(output.result) {
//TODO: Show dialog
case DCDResult.FAIL:
case DCDResult.DCD_NOT_RUNNING:
case DCDResult.NO_RESULT:
editor.setFocus();
return false;
case DCDResult.SUCCESS:
auto target = to!int(output.output[1]);
if(output.output[0].indexOf("stdin".dup) != -1) {
auto fileName = output.fileName;
if(fileName.indexOf("stdin") == 0) {
Log.d("Declaration is in current file. Jumping to it.");
auto destPos = byteOffsetToCaret(content, target);
editor.setCaretPos(destPos.line,destPos.pos);
editor.setFocus();
}
else {
} else {
//Must open file first to get the content for finding the correct caret position.
_frame.openSourceFile(to!string(output.output[0]));
string txt;
txt = toUTF8(_frame.currentEditor.text);
auto destPos = byteOffsetToCaret(txt, target);
_frame.currentEditor.setCaretPos(destPos.line,destPos.pos);
_frame.currentEditor.setFocus();
_frame.openSourceFile(to!string(fileName));
content = toUTF8(_frame.currentEditor.text);
}
auto target = to!int(output.offset);
auto destPos = byteOffsetToCaret(content, target);
_frame.currentEditor.setCaretPos(destPos.line,destPos.pos);
_frame.currentEditor.setFocus();
return true;
default:
return false;
@ -63,14 +60,14 @@ class DEditorTool : EditorTool
override dstring[] getCompletions(DSourceEdit editor, TextPosition caretPosition) {
string[] importPaths = editor.importPaths();
_frame.moduleCache.addImportPaths(importPaths);
string content = toUTF8(editor.text);
auto byteOffset = caretPositionToByteOffset(content, caretPosition);
ResultSet output = _dcd.getCompletions(importPaths, editor.filename, content, byteOffset);
ResultSet output = _dcd.getCompletions(importPaths, editor.filename, content, byteOffset, _frame.moduleCache);
switch(output.result) {
//TODO: Show dialog
case DCDResult.FAIL:
case DCDResult.DCD_NOT_RUNNING:
case DCDResult.NO_RESULT:
case DCDResult.SUCCESS:
default:

View File

@ -26,7 +26,7 @@ import dlangide.ui.dsourceedit;
import dlangide.ui.homescreen;
import dlangide.ui.settings;
import dlangide.ui.debuggerui;
import dlangide.tools.d.dcdserver;
import dlangide.workspace.workspace;
import dlangide.workspace.project;
import dlangide.builders.builder;
@ -76,7 +76,11 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
OutputPanel _logPanel;
DockHost _dockHost;
TabWidget _tabs;
DCDServer _dcdServer;
///Cache for parsed D files for autocomplete and symbol finding
import dsymbol.modulecache;
ModuleCache _moduleCache = ModuleCache(new ASTAllocator);
IDESettings _settings;
ProgramExecution _execution;
@ -91,6 +95,7 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
applySettings(_settings);
}
@property ref ModuleCache moduleCache() { return _moduleCache; }
@property DockHost dockHost() { return _dockHost; }
@property OutputPanel logPanel() { return _logPanel; }
@ -260,7 +265,6 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
override protected void init() {
_appName = "dlangide";
//_editorTool = new DEditorTool(this);
_dcdServer = new DCDServer();
_settings = new IDESettings(buildNormalizedPath(settingsDir, "settings.json"));
_settings.load();
_settings.updateDefaults();
@ -553,12 +557,6 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
_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;
@ -1299,12 +1297,6 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
void onWindowClose() {
Log.i("onWindowClose()");
stopExecution();
if (_dcdServer) {
if (_dcdServer.isRunning)
_dcdServer.stop();
destroy(_dcdServer);
_dcdServer = null;
}
}
}