From 115e20ba797742e43eb4c44a9dd0e0890f0db2b5 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Tue, 17 Feb 2015 16:01:12 +0300 Subject: [PATCH] DCD support improvements --- dub.json | 2 +- src/dlangide/builders/extprocess.d | 5 +-- src/dlangide/tools/d/dcdinterface.d | 53 ++++++++++++++++++++--------- src/dlangide/tools/d/dcdserver.d | 16 ++++----- src/dlangide/tools/d/deditortool.d | 22 +++++++----- src/dlangide/ui/commands.d | 4 +-- src/dlangide/ui/dsourceedit.d | 26 ++++++++++++-- src/dlangide/ui/frame.d | 2 +- 8 files changed, 87 insertions(+), 43 deletions(-) diff --git a/dub.json b/dub.json index 6bc42b6..3e8bb84 100644 --- a/dub.json +++ b/dub.json @@ -11,7 +11,7 @@ "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"], + "copyFiles-windows": ["lib/win32/FreeImage.dll", "lib/win32/SDL2.dll", "lib/win32/dcd-server.exe", "lib/win32/dcd-client.exe"], "dependencies": { "dlangui": "~master" diff --git a/src/dlangide/builders/extprocess.d b/src/dlangide/builders/extprocess.d index 2545ea0..9d782e9 100644 --- a/src/dlangide/builders/extprocess.d +++ b/src/dlangide/builders/extprocess.d @@ -400,12 +400,13 @@ class ExternalProcess { return _state; } - void write(dstring data) { + void write(string data) { if(_state == ExternalProcessState.Error || _state == ExternalProcessState.None || _state == ExternalProcessState.Stopped) { return; } else { - _pipes.stdin.write(data); + Log.d("writing ", data.length, " characters to stdin"); + _pipes.stdin.write("", data); _pipes.stdin.close(); } } diff --git a/src/dlangide/tools/d/dcdinterface.d b/src/dlangide/tools/d/dcdinterface.d index 9fddab0..b87a6d4 100644 --- a/src/dlangide/tools/d/dcdinterface.d +++ b/src/dlangide/tools/d/dcdinterface.d @@ -34,7 +34,20 @@ class DCDInterface { //stdoutTarget = new ProtectedTextStorage(); } - protected dstring[] invokeDcd(string[] arguments, dstring content, out bool success) { + protected string dumpContext(string content, int pos) { + if (pos >= 0 && pos <= content.length) { + int start = pos; + int end = pos; + for (int i = 0; start > 0 && content[start - 1] != '\n' && i < 10; i++) + start--; + for (int i = 0; end < content.length - 1 && content[end] != '\n' && i < 10; i++) + end++; + return content[start .. pos] ~ "|" ~ content[pos .. end]; + } + return ""; + } + + protected dstring[] invokeDcd(string[] arguments, string content, out bool success) { success = false; ExternalProcess dcdProcess = new ExternalProcess(); @@ -48,6 +61,7 @@ class DCDInterface { string dcd_client_dir = "/usr/bin"; } dcdProcess.run(dcd_client_name, arguments, dcd_client_dir, stdoutTarget); + dcdProcess.write(content); dcdProcess.wait(); @@ -59,14 +73,16 @@ class DCDInterface { return output; } - ResultSet goToDefinition(in string[] importPaths, in dstring content, int index) { + ResultSet goToDefinition(in string[] importPaths, in string content, int index) { ResultSet result; + debug(DCD) Log.d("DCD Context: ", dumpContext(content, index)); + string[] arguments = ["-l", "-c"]; arguments ~= [to!string(index)]; + foreach(p; importPaths) { - arguments ~= "-I"; - arguments ~= p; + arguments ~= "-I" ~ p; } if (_port != DCD_DEFAULT_PORT) arguments ~= "-p" ~ to!string(_port); @@ -84,25 +100,31 @@ class DCDInterface { debug(DCD) Log.d("DCD output:\n", output); if(output.length > 0) { - if(output[0].indexOf("Not Found".dup) == 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; + } - auto split = output[0].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 { + result.result = DCDResult.NO_RESULT; + //result.result = DCDResult.FAIL; } - result.output ~= output[0][0 .. split]; - result.output ~= output[0][split+1 .. $]; return result; } - ResultSet getCompletions(in string[] importPaths, in dstring content, int index) { + ResultSet getCompletions(in string[] importPaths, in string content, int index) { + + debug(DCD) Log.d("DCD Context: ", dumpContext(content, index)); ResultSet result; @@ -110,8 +132,7 @@ class DCDInterface { arguments ~= [to!string(index)]; foreach(p; importPaths) { - arguments ~= "-I"; - arguments ~= p; + arguments ~= "-I" ~ p; } if (_port != DCD_DEFAULT_PORT) arguments ~= "-p" ~ to!string(_port); diff --git a/src/dlangide/tools/d/dcdserver.d b/src/dlangide/tools/d/dcdserver.d index 2a5b097..cc9e279 100644 --- a/src/dlangide/tools/d/dcdserver.d +++ b/src/dlangide/tools/d/dcdserver.d @@ -48,11 +48,8 @@ class DCDServer { string[] srcPaths = dmdSourcePaths(); string[] arguments; - arguments ~= ("-p" ~ to!string(_port)); - foreach(p; srcPaths) { - arguments ~= "-I"; - arguments ~= p; - } + 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); @@ -73,17 +70,18 @@ class DCDServer { _running = true; return true; } + /// stop DCD server bool stop() { if (!dcdProcess) { - Log.e("Cannot stop DCD - it's not started"); + Log.e("Cannot stop DCD server - it's not started"); return false; } - Log.i("Current DCD state: ", dcdProcess.poll()); - Log.i("Killing DCD server"); + debug(DCD) Log.i("Current DCD server state: ", dcdProcess.poll()); + Log.i("Stopping DCD server"); ExternalProcessState state = dcdProcess.kill(); state = dcdProcess.wait(); - Log.i("DCD state: ", state); + debug(DCD) Log.i("DCD server state: ", state); destroy(dcdProcess); dcdProcess = null; stdoutTarget = null; diff --git a/src/dlangide/tools/d/deditortool.d b/src/dlangide/tools/d/deditortool.d index 9c98225..60e4184 100644 --- a/src/dlangide/tools/d/deditortool.d +++ b/src/dlangide/tools/d/deditortool.d @@ -7,6 +7,7 @@ import dlangui.widgets.editors; import dlangide.ui.frame; import std.stdio; import std.string; +import std.utf; import dlangui.core.logger; import std.conv; @@ -25,8 +26,9 @@ class DEditorTool : EditorTool override bool goToDefinition(DSourceEdit editor, TextPosition caretPosition) { string[] importPaths = editor.importPaths(); - auto byteOffset = caretPositionToByteOffset(editor.text, caretPosition); - ResultSet output = _dcd.goToDefinition(importPaths, editor.text, byteOffset); + string content = toUTF8(editor.text); + auto byteOffset = caretPositionToByteOffset(content, caretPosition); + ResultSet output = _dcd.goToDefinition(importPaths, content, byteOffset); switch(output.result) { @@ -39,13 +41,15 @@ class DEditorTool : EditorTool auto target = to!int(output.output[1]); if(output.output[0].indexOf("stdin".dup) != -1) { Log.d("Declaration is in current file. Jumping to it."); - auto destPos = byteOffsetToCaret(editor.text, target); + auto destPos = byteOffsetToCaret(content, target); editor.setCaretPos(destPos.line,destPos.pos); } else { //Must open file first to get the content for finding the correct caret position. _frame.openSourceFile(to!string(output.output[0])); - auto destPos = byteOffsetToCaret(_frame.currentEditor.text(), target); + string txt; + txt = toUTF8(_frame.currentEditor.text); + auto destPos = byteOffsetToCaret(txt, target); _frame.currentEditor.setCaretPos(destPos.line,destPos.pos); } return true; @@ -57,8 +61,9 @@ class DEditorTool : EditorTool override dstring[] getCompletions(DSourceEdit editor, TextPosition caretPosition) { string[] importPaths = editor.importPaths(); - auto byteOffset = caretPositionToByteOffset(editor.text, caretPosition); - ResultSet output = _dcd.getCompletions(importPaths, editor.text, byteOffset); + string content = toUTF8(editor.text); + auto byteOffset = caretPositionToByteOffset(content, caretPosition); + ResultSet output = _dcd.getCompletions(importPaths, content, byteOffset); switch(output.result) { //TODO: Show dialog case DCDResult.FAIL: @@ -73,8 +78,7 @@ class DEditorTool : EditorTool private: DCDInterface _dcd; - // TODO: non-ascii characters support - int caretPositionToByteOffset(dstring content, TextPosition caretPosition) { + int caretPositionToByteOffset(string content, TextPosition caretPosition) { auto line = 0; auto pos = 0; auto bytes = 0; @@ -92,7 +96,7 @@ private: return bytes; } - TextPosition byteOffsetToCaret(dstring content, int byteOffset) { + TextPosition byteOffsetToCaret(string content, int byteOffset) { int bytes = 0; int line = 0; int pos = 0; diff --git a/src/dlangide/ui/commands.d b/src/dlangide/ui/commands.d index b6d88c9..3c43f7d 100644 --- a/src/dlangide/ui/commands.d +++ b/src/dlangide/ui/commands.d @@ -97,5 +97,5 @@ const Action ACTION_WINDOW_CLOSE_ALL_DOCUMENTS = new Action(IDEActions.WindowClo const Action ACTION_CREATE_NEW_WORKSPACE = new Action(IDEActions.CreateNewWorkspace, "Create new workspace"d); const Action ACTION_ADD_TO_CURRENT_WORKSPACE = new Action(IDEActions.AddToCurrentWorkspace, "Add to current workspace"d); -const Action ACTION_GO_TO_DEFINITION = new Action(IDEActions.GoToDefinition, "GO_TO_DEFINITION"c, ""c, KeyCode.KEY_G, KeyFlag.Control); -const Action ACTION_GET_COMPLETIONS = new Action(IDEActions.GetCompletionSuggestions, "SHOW_COMPLETIONS"c, ""c, KeyCode.KEY_G, KeyFlag.Control|KeyFlag.Shift); +const Action ACTION_GO_TO_DEFINITION = (new Action(IDEActions.GoToDefinition, "GO_TO_DEFINITION"c, ""c, KeyCode.KEY_G, KeyFlag.Control)).addAccelerator(KeyCode.F12, 0).disableByDefault(); +const Action ACTION_GET_COMPLETIONS = (new Action(IDEActions.GetCompletionSuggestions, "SHOW_COMPLETIONS"c, ""c, KeyCode.KEY_G, KeyFlag.Control|KeyFlag.Shift)).addAccelerator(KeyCode.SPACE, KeyFlag.Control).disableByDefault(); diff --git a/src/dlangide/ui/dsourceedit.d b/src/dlangide/ui/dsourceedit.d index 891561c..ec43bb0 100644 --- a/src/dlangide/ui/dsourceedit.d +++ b/src/dlangide/ui/dsourceedit.d @@ -32,7 +32,8 @@ class DSourceEdit : SourceEdit { setTokenHightlightColor(TokenCategory.Comment_Documentation, 0x206000); //setTokenHightlightColor(TokenCategory.Identifier, 0x206000); // no colors MenuItem editPopupItem = new MenuItem(null); - editPopupItem.add(ACTION_EDIT_COPY, ACTION_EDIT_PASTE, ACTION_EDIT_CUT, ACTION_EDIT_UNDO, ACTION_EDIT_REDO, ACTION_EDIT_INDENT, ACTION_EDIT_UNINDENT, ACTION_EDIT_TOGGLE_LINE_COMMENT, ACTION_GET_COMPLETIONS); + editPopupItem.add(ACTION_EDIT_COPY, ACTION_EDIT_PASTE, ACTION_EDIT_CUT, ACTION_EDIT_UNDO, ACTION_EDIT_REDO, ACTION_EDIT_INDENT, ACTION_EDIT_UNINDENT, ACTION_EDIT_TOGGLE_LINE_COMMENT, ACTION_GET_COMPLETIONS, ACTION_GO_TO_DEFINITION); + //ACTION_GO_TO_DEFINITION, ACTION_GET_COMPLETIONS popupMenu = editPopupItem; showIcons = true; showFolding = true; @@ -50,8 +51,12 @@ class DSourceEdit : SourceEdit { return res; } + @property bool isDSourceFile() { + return filename.endsWith(".d") || filename.endsWith(".dd") || filename.endsWith(".dh") || filename.endsWith(".ddoc"); + } + void setHighlighter() { - if (filename.endsWith(".d") || filename.endsWith(".dd") || filename.endsWith(".dh") || filename.endsWith(".ddoc")) { + if (isDSourceFile) { content.syntaxHighlighter = new SimpleDSyntaxHighlighter(filename); } else { content.syntaxHighlighter = null; @@ -61,7 +66,7 @@ class DSourceEdit : SourceEdit { /// returns project import paths - if file from project is opened in current editor string[] importPaths() { if (_projectSourceFile) - return _projectSourceFile.project.sourcePaths; + return _projectSourceFile.project.sourcePaths ~ _projectSourceFile.project.builderSourcePaths; return null; } @@ -100,6 +105,21 @@ class DSourceEdit : SourceEdit { return super.handleAction(a); } + /// override to handle specific actions state (e.g. change enabled state for supported actions) + override bool handleActionStateRequest(const Action a) { + switch (a.id) { + case IDEActions.GoToDefinition: + case IDEActions.GetCompletionSuggestions: + if (isDSourceFile) + a.state = ACTION_STATE_ENABLED; + else + a.state = ACTION_STATE_DISABLE; + return true; + default: + return super.handleActionStateRequest(a); + } + } + void showCompletionPopup(dstring[] suggestions) { if(suggestions.length == 0) { diff --git a/src/dlangide/ui/frame.d b/src/dlangide/ui/frame.d index aa1b91f..e4a0f19 100644 --- a/src/dlangide/ui/frame.d +++ b/src/dlangide/ui/frame.d @@ -352,7 +352,7 @@ class IDEFrame : AppFrame { editItem.add(ACTION_EDIT_COPY, ACTION_EDIT_PASTE, ACTION_EDIT_CUT, ACTION_EDIT_UNDO, ACTION_EDIT_REDO); MenuItem editItemAdvanced = new MenuItem(new Action(221, "MENU_EDIT_ADVANCED")); - editItemAdvanced.add(ACTION_EDIT_INDENT, ACTION_EDIT_UNINDENT, ACTION_EDIT_TOGGLE_LINE_COMMENT, ACTION_EDIT_TOGGLE_BLOCK_COMMENT); + editItemAdvanced.add(ACTION_EDIT_INDENT, ACTION_EDIT_UNINDENT, ACTION_EDIT_TOGGLE_LINE_COMMENT, ACTION_EDIT_TOGGLE_BLOCK_COMMENT, ACTION_GO_TO_DEFINITION, ACTION_GET_COMPLETIONS); editItem.add(editItemAdvanced); editItem.add(ACTION_EDIT_PREFERENCES);