From 4394f834cb901f0acf80c4381ab16a3b4854cc23 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Thu, 28 Jan 2016 10:26:12 +0300 Subject: [PATCH] DCD async access - for #93 --- dub.json | 2 +- src/dlangide/tools/d/dcdinterface.d | 114 +++++++++++++++++++--------- src/dlangide/tools/d/deditortool.d | 113 +++++++++++++++------------ 3 files changed, 143 insertions(+), 86 deletions(-) diff --git a/dub.json b/dub.json index 993ad7c..954f9e9 100644 --- a/dub.json +++ b/dub.json @@ -12,7 +12,7 @@ "stringImportPaths": ["views", "views/res", "views/res/i18n", "views/res/mdpi", "views/res/hdpi"], "dependencies": { - "dlangui": "~>0.7.59", + "dlangui": "~>0.7.60", "dcd": "~>0.7.5" }, diff --git a/src/dlangide/tools/d/dcdinterface.d b/src/dlangide/tools/d/dcdinterface.d index e67e2e6..c8d81c7 100644 --- a/src/dlangide/tools/d/dcdinterface.d +++ b/src/dlangide/tools/d/dcdinterface.d @@ -2,6 +2,7 @@ module dlangide.tools.d.dcdinterface; import dlangui.core.logger; import dlangui.core.files; +import dlangui.platforms.common.platform; import ddebug.common.queue; import core.thread; @@ -20,13 +21,19 @@ alias DocCommentsResultSet = Tuple!(DCDResult, "result", string[], "docComments" alias FindDeclarationResultSet = Tuple!(DCDResult, "result", string, "fileName", ulong, "offset"); alias ResultSet = Tuple!(DCDResult, "result", dstring[], "output"); +import server.autocomplete; +import common.messages; + class DCDTask { protected bool _cancelled; + protected CustomEventTarget _guiExecutor; protected string[] _importPaths; protected string _filename; protected string _content; protected int _index; - this(string[] importPaths, in string filename, in string content, int index) { + protected AutocompleteRequest request; + this(CustomEventTarget guiExecutor, string[] importPaths, in string filename, in string content, int index) { + _guiExecutor = guiExecutor; _importPaths = importPaths; _filename = filename; _content = content; @@ -34,14 +41,35 @@ class DCDTask { } @property bool cancelled() { return _cancelled; } void cancel() { - _cancelled = true; + synchronized(this) { + _cancelled = true; + } + } + void createRequest() { + request.sourceCode = cast(ubyte[])_content; + request.fileName = _filename; + request.cursorPosition = _index; + } + void performRequest() { + // override + } + void postResults() { + // override } void execute() { - // override + if (_cancelled) + return; + createRequest(); + performRequest(); + synchronized(this) { + if (_cancelled) + return; + _guiExecutor.executeInUiThread(&postResults); + } } } -/// Interface to DCD +/// Async interface to DCD class DCDInterface : Thread { import dsymbol.modulecache; @@ -51,6 +79,7 @@ class DCDInterface : Thread { this() { super(&threadFunc); _queue = new BlockingQueue!DCDTask(); + name = "DCDthread"; start(); } @@ -74,15 +103,15 @@ class DCDInterface : Thread { DCDTask task; if (!_queue.get(task)) break; - if (task && !task.cancelled) + if (task && !task.cancelled) { + Log.d("Execute DCD task"); task.execute(); + Log.d("DCD task execution finished"); + } } Log.d("Exiting DCD tasks thread"); } - import server.autocomplete; - import common.messages; - import dsymbol.modulecache; protected string dumpContext(string content, int pos) { @@ -98,7 +127,7 @@ class DCDInterface : Thread { return ""; } - DocCommentsResultSet getDocComments(in string[] importPaths, in string filename, in string content, int index) { + DocCommentsResultSet getDocComments(CustomEventTarget guiExecutor, in string[] importPaths, in string filename, in string content, int index) { debug(DCD) Log.d("getDocComments: ", dumpContext(content, index)); AutocompleteRequest request; request.sourceCode = cast(ubyte[])content; @@ -119,30 +148,44 @@ class DCDInterface : Thread { return result; } - void goToDefinition(in string[] importPaths, in string filename, in string content, int index, void delegate(FindDeclarationResultSet res) callback) { + /// DCD go to definition task + class GoToDefinitionTask : DCDTask { - debug(DCD) Log.d("DCD Context: ", dumpContext(content, index)); - AutocompleteRequest request; - request.sourceCode = cast(ubyte[])content; - request.fileName = filename; - request.cursorPosition = index; + protected void delegate(FindDeclarationResultSet output) _callback; + protected FindDeclarationResultSet result; - AutocompleteResponse response = findDeclaration(request, *getModuleCache(importPaths)); - - FindDeclarationResultSet result; - result.fileName = response.symbolFilePath; - result.offset = response.symbolLocation; - result.result = DCDResult.SUCCESS; - - debug(DCD) Log.d("DCD fileName:\n", result.fileName); - - if (result.fileName is null) { - result.result = DCDResult.NO_RESULT; + this(CustomEventTarget guiExecutor, string[] importPaths, in string filename, in string content, int index, void delegate(FindDeclarationResultSet output) callback) { + super(guiExecutor, importPaths, filename, content, index); + _callback = callback; + } + + override void performRequest() { + AutocompleteResponse response = findDeclaration(request, *getModuleCache(_importPaths)); + + result.fileName = response.symbolFilePath; + result.offset = response.symbolLocation; + result.result = DCDResult.SUCCESS; + + debug(DCD) Log.d("DCD fileName:\n", result.fileName); + + if (result.fileName is null) { + result.result = DCDResult.NO_RESULT; + } + } + override void postResults() { + _callback(result); } - callback(result); } - ResultSet getCompletions(in string[] importPaths, in string filename, in string content, int index) { + DCDTask goToDefinition(CustomEventTarget guiExecutor, string[] importPaths, in string filename, in string content, int index, void delegate(FindDeclarationResultSet res) callback) { + + debug(DCD) Log.d("DCD Context: ", dumpContext(content, index)); + GoToDefinitionTask task = new GoToDefinitionTask(guiExecutor, importPaths, filename, content, index, callback); + _queue.put(task); + return task; + } + + ResultSet getCompletions(CustomEventTarget guiExecutor, in string[] importPaths, in string filename, in string content, int index) { debug(DCD) Log.d("DCD Context: ", dumpContext(content, index)); ResultSet result; @@ -175,14 +218,12 @@ class DCDInterface : Thread { protected void delegate(DocCommentsResultSet output) _callback; protected DocCommentsResultSet result; - this(string[] importPaths, in string filename, in string content, int index, void delegate(DocCommentsResultSet output) callback) { - super(importPaths, filename, content, index); + this(CustomEventTarget guiExecutor, string[] importPaths, in string filename, in string content, int index, void delegate(DocCommentsResultSet output) callback) { + super(guiExecutor, importPaths, filename, content, index); _callback = callback; } - override void execute() { - if (_cancelled) - return; + override void performRequest() { AutocompleteRequest request; request.sourceCode = cast(ubyte[])_content; request.fileName = _filename; @@ -198,9 +239,10 @@ class DCDInterface : Thread { if (result.docComments is null) { result.result = DCDResult.NO_RESULT; } - - if (!_cancelled) - _callback(result); + } + override void postResults() { + _callback(result); } } + } diff --git a/src/dlangide/tools/d/deditortool.d b/src/dlangide/tools/d/deditortool.d index 612f8bc..016259d 100644 --- a/src/dlangide/tools/d/deditortool.d +++ b/src/dlangide/tools/d/deditortool.d @@ -21,12 +21,16 @@ class DEditorTool : EditorTool super(frame); } + ~this() { + cancelGoToDefinition(); + } + override string[] getDocComments(DSourceEdit editor, TextPosition caretPosition) { string[] importPaths = editor.importPaths(); string content = toUTF8(editor.text); auto byteOffset = caretPositionToByteOffset(content, caretPosition); - DocCommentsResultSet output = _frame.dcdInterface.getDocComments(importPaths, editor.filename, content, byteOffset); + DocCommentsResultSet output = _frame.dcdInterface.getDocComments(editor.window, importPaths, editor.filename, content, byteOffset); switch(output.result) { //TODO: Show dialog @@ -45,14 +49,21 @@ class DEditorTool : EditorTool override void cancelGoToDefinition() { // override it + if (_goToDefinitionTask) { + _goToDefinitionTask.cancel(); + _goToDefinitionTask = null; + } } + DCDTask _goToDefinitionTask; override void goToDefinition(DSourceEdit editor, TextPosition caretPosition) { + cancelGoToDefinition(); string[] importPaths = editor.importPaths(); - string content = toUTF8(editor.text); auto byteOffset = caretPositionToByteOffset(content, caretPosition); - _frame.dcdInterface.goToDefinition(importPaths, editor.filename, content, byteOffset, delegate(FindDeclarationResultSet output) { + + + _goToDefinitionTask = _frame.dcdInterface.goToDefinition(editor.window, importPaths, editor.filename, content, byteOffset, delegate(FindDeclarationResultSet output) { // handle result switch(output.result) { //TODO: Show dialog @@ -80,6 +91,7 @@ class DEditorTool : EditorTool default: break; } + _goToDefinitionTask = null; }); } @@ -89,7 +101,7 @@ class DEditorTool : EditorTool string content = toUTF8(editor.text); auto byteOffset = caretPositionToByteOffset(content, caretPosition); - ResultSet output = _frame.dcdInterface.getCompletions(importPaths, editor.filename, content, byteOffset); + ResultSet output = _frame.dcdInterface.getCompletions(editor.window, importPaths, editor.filename, content, byteOffset); switch(output.result) { //TODO: Show dialog case DCDResult.FAIL: @@ -102,49 +114,52 @@ class DEditorTool : EditorTool private: - static int caretPositionToByteOffset(string content, TextPosition caretPosition) { - auto line = 0; - auto pos = 0; - auto bytes = 0; - foreach(c; content) { - if(line == caretPosition.line) { - if(pos == caretPosition.pos) - break; - pos++; - } else if (line > caretPosition.line) { - break; - } - bytes++; - if(c == '\n') { - line++; - pos = 0; - } - } - return bytes; - } - - static TextPosition byteOffsetToCaret(string content, int byteOffset) { - int bytes = 0; - int line = 0; - int pos = 0; - TextPosition textPos; - foreach(c; content) { - if(bytes == byteOffset) { - //We all good. - textPos.line = line; - textPos.pos = pos; - return textPos; - } - bytes++; - if(c == '\n') - { - line++; - pos = 0; - } - else { - pos++; - } - } - return textPos; - } +} + +/// convert caret position to byte offset in utf8 content +int caretPositionToByteOffset(string content, TextPosition caretPosition) { + auto line = 0; + auto pos = 0; + auto bytes = 0; + foreach(c; content) { + if(line == caretPosition.line) { + if(pos == caretPosition.pos) + break; + pos++; + } else if (line > caretPosition.line) { + break; + } + bytes++; + if(c == '\n') { + line++; + pos = 0; + } + } + return bytes; +} + +/// convert byte offset in utf8 content to caret position +TextPosition byteOffsetToCaret(string content, int byteOffset) { + int bytes = 0; + int line = 0; + int pos = 0; + TextPosition textPos; + foreach(c; content) { + if(bytes == byteOffset) { + //We all good. + textPos.line = line; + textPos.pos = pos; + return textPos; + } + bytes++; + if(c == '\n') + { + line++; + pos = 0; + } + else { + pos++; + } + } + return textPos; }