DCD async access - for #93

This commit is contained in:
Vadim Lopatin 2016-01-28 10:26:12 +03:00
parent d828af306e
commit 4394f834cb
3 changed files with 143 additions and 86 deletions

View File

@ -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"
},

View File

@ -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);
}
}
}

View File

@ -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;
}