mirror of https://github.com/buggins/dlangide.git
DCD support improvements
This commit is contained in:
parent
0ae570dd26
commit
115e20ba79
2
dub.json
2
dub.json
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
"stringImportPaths": ["views", "views/res", "views/res/i18n", "views/res/mdpi"],
|
"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": {
|
"dependencies": {
|
||||||
"dlangui": "~master"
|
"dlangui": "~master"
|
||||||
|
|
|
@ -400,12 +400,13 @@ class ExternalProcess {
|
||||||
return _state;
|
return _state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(dstring data) {
|
void write(string data) {
|
||||||
if(_state == ExternalProcessState.Error || _state == ExternalProcessState.None || _state == ExternalProcessState.Stopped) {
|
if(_state == ExternalProcessState.Error || _state == ExternalProcessState.None || _state == ExternalProcessState.Stopped) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_pipes.stdin.write(data);
|
Log.d("writing ", data.length, " characters to stdin");
|
||||||
|
_pipes.stdin.write("", data);
|
||||||
_pipes.stdin.close();
|
_pipes.stdin.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,20 @@ class DCDInterface {
|
||||||
//stdoutTarget = new ProtectedTextStorage();
|
//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;
|
success = false;
|
||||||
ExternalProcess dcdProcess = new ExternalProcess();
|
ExternalProcess dcdProcess = new ExternalProcess();
|
||||||
|
|
||||||
|
@ -48,6 +61,7 @@ class DCDInterface {
|
||||||
string dcd_client_dir = "/usr/bin";
|
string dcd_client_dir = "/usr/bin";
|
||||||
}
|
}
|
||||||
dcdProcess.run(dcd_client_name, arguments, dcd_client_dir, stdoutTarget);
|
dcdProcess.run(dcd_client_name, arguments, dcd_client_dir, stdoutTarget);
|
||||||
|
|
||||||
dcdProcess.write(content);
|
dcdProcess.write(content);
|
||||||
dcdProcess.wait();
|
dcdProcess.wait();
|
||||||
|
|
||||||
|
@ -59,14 +73,16 @@ class DCDInterface {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultSet goToDefinition(in string[] importPaths, in dstring content, int index) {
|
ResultSet goToDefinition(in string[] importPaths, in string content, int index) {
|
||||||
ResultSet result;
|
ResultSet result;
|
||||||
|
|
||||||
|
debug(DCD) Log.d("DCD Context: ", dumpContext(content, index));
|
||||||
|
|
||||||
string[] arguments = ["-l", "-c"];
|
string[] arguments = ["-l", "-c"];
|
||||||
arguments ~= [to!string(index)];
|
arguments ~= [to!string(index)];
|
||||||
|
|
||||||
foreach(p; importPaths) {
|
foreach(p; importPaths) {
|
||||||
arguments ~= "-I";
|
arguments ~= "-I" ~ p;
|
||||||
arguments ~= p;
|
|
||||||
}
|
}
|
||||||
if (_port != DCD_DEFAULT_PORT)
|
if (_port != DCD_DEFAULT_PORT)
|
||||||
arguments ~= "-p" ~ to!string(_port);
|
arguments ~= "-p" ~ to!string(_port);
|
||||||
|
@ -84,25 +100,31 @@ class DCDInterface {
|
||||||
debug(DCD) Log.d("DCD output:\n", output);
|
debug(DCD) Log.d("DCD output:\n", output);
|
||||||
|
|
||||||
if(output.length > 0) {
|
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;
|
result.result = DCDResult.NO_RESULT;
|
||||||
return 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");
|
result.output ~= output[0][0 .. split];
|
||||||
if(split == -1) {
|
result.output ~= output[0][split+1 .. $];
|
||||||
Log.d("DCD output format error.");
|
} else {
|
||||||
result.result = DCDResult.FAIL;
|
result.result = DCDResult.NO_RESULT;
|
||||||
return result;
|
//result.result = DCDResult.FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.output ~= output[0][0 .. split];
|
|
||||||
result.output ~= output[0][split+1 .. $];
|
|
||||||
return result;
|
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;
|
ResultSet result;
|
||||||
|
|
||||||
|
@ -110,8 +132,7 @@ class DCDInterface {
|
||||||
arguments ~= [to!string(index)];
|
arguments ~= [to!string(index)];
|
||||||
|
|
||||||
foreach(p; importPaths) {
|
foreach(p; importPaths) {
|
||||||
arguments ~= "-I";
|
arguments ~= "-I" ~ p;
|
||||||
arguments ~= p;
|
|
||||||
}
|
}
|
||||||
if (_port != DCD_DEFAULT_PORT)
|
if (_port != DCD_DEFAULT_PORT)
|
||||||
arguments ~= "-p" ~ to!string(_port);
|
arguments ~= "-p" ~ to!string(_port);
|
||||||
|
|
|
@ -48,11 +48,8 @@ class DCDServer {
|
||||||
|
|
||||||
string[] srcPaths = dmdSourcePaths();
|
string[] srcPaths = dmdSourcePaths();
|
||||||
string[] arguments;
|
string[] arguments;
|
||||||
arguments ~= ("-p" ~ to!string(_port));
|
foreach(p; srcPaths)
|
||||||
foreach(p; srcPaths) {
|
arguments ~= "-I" ~ p;
|
||||||
arguments ~= "-I";
|
|
||||||
arguments ~= p;
|
|
||||||
}
|
|
||||||
if (_port != DCD_DEFAULT_PORT)
|
if (_port != DCD_DEFAULT_PORT)
|
||||||
arguments ~= "-p" ~ to!string(_port);
|
arguments ~= "-p" ~ to!string(_port);
|
||||||
Log.i("starting dcd-server: executable path is ", dcdServerExecutable, " args: ", arguments);
|
Log.i("starting dcd-server: executable path is ", dcdServerExecutable, " args: ", arguments);
|
||||||
|
@ -73,17 +70,18 @@ class DCDServer {
|
||||||
_running = true;
|
_running = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// stop DCD server
|
/// stop DCD server
|
||||||
bool stop() {
|
bool stop() {
|
||||||
if (!dcdProcess) {
|
if (!dcdProcess) {
|
||||||
Log.e("Cannot stop DCD - it's not started");
|
Log.e("Cannot stop DCD server - it's not started");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Log.i("Current DCD state: ", dcdProcess.poll());
|
debug(DCD) Log.i("Current DCD server state: ", dcdProcess.poll());
|
||||||
Log.i("Killing DCD server");
|
Log.i("Stopping DCD server");
|
||||||
ExternalProcessState state = dcdProcess.kill();
|
ExternalProcessState state = dcdProcess.kill();
|
||||||
state = dcdProcess.wait();
|
state = dcdProcess.wait();
|
||||||
Log.i("DCD state: ", state);
|
debug(DCD) Log.i("DCD server state: ", state);
|
||||||
destroy(dcdProcess);
|
destroy(dcdProcess);
|
||||||
dcdProcess = null;
|
dcdProcess = null;
|
||||||
stdoutTarget = null;
|
stdoutTarget = null;
|
||||||
|
|
|
@ -7,6 +7,7 @@ import dlangui.widgets.editors;
|
||||||
import dlangide.ui.frame;
|
import dlangide.ui.frame;
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
import std.string;
|
import std.string;
|
||||||
|
import std.utf;
|
||||||
import dlangui.core.logger;
|
import dlangui.core.logger;
|
||||||
|
|
||||||
import std.conv;
|
import std.conv;
|
||||||
|
@ -25,8 +26,9 @@ class DEditorTool : EditorTool
|
||||||
|
|
||||||
override bool goToDefinition(DSourceEdit editor, TextPosition caretPosition) {
|
override bool goToDefinition(DSourceEdit editor, TextPosition caretPosition) {
|
||||||
string[] importPaths = editor.importPaths();
|
string[] importPaths = editor.importPaths();
|
||||||
auto byteOffset = caretPositionToByteOffset(editor.text, caretPosition);
|
string content = toUTF8(editor.text);
|
||||||
ResultSet output = _dcd.goToDefinition(importPaths, editor.text, byteOffset);
|
auto byteOffset = caretPositionToByteOffset(content, caretPosition);
|
||||||
|
ResultSet output = _dcd.goToDefinition(importPaths, content, byteOffset);
|
||||||
|
|
||||||
|
|
||||||
switch(output.result) {
|
switch(output.result) {
|
||||||
|
@ -39,13 +41,15 @@ class DEditorTool : EditorTool
|
||||||
auto target = to!int(output.output[1]);
|
auto target = to!int(output.output[1]);
|
||||||
if(output.output[0].indexOf("stdin".dup) != -1) {
|
if(output.output[0].indexOf("stdin".dup) != -1) {
|
||||||
Log.d("Declaration is in current file. Jumping to it.");
|
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);
|
editor.setCaretPos(destPos.line,destPos.pos);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//Must open file first to get the content for finding the correct caret position.
|
//Must open file first to get the content for finding the correct caret position.
|
||||||
_frame.openSourceFile(to!string(output.output[0]));
|
_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);
|
_frame.currentEditor.setCaretPos(destPos.line,destPos.pos);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -57,8 +61,9 @@ class DEditorTool : EditorTool
|
||||||
override dstring[] getCompletions(DSourceEdit editor, TextPosition caretPosition) {
|
override dstring[] getCompletions(DSourceEdit editor, TextPosition caretPosition) {
|
||||||
string[] importPaths = editor.importPaths();
|
string[] importPaths = editor.importPaths();
|
||||||
|
|
||||||
auto byteOffset = caretPositionToByteOffset(editor.text, caretPosition);
|
string content = toUTF8(editor.text);
|
||||||
ResultSet output = _dcd.getCompletions(importPaths, editor.text, byteOffset);
|
auto byteOffset = caretPositionToByteOffset(content, caretPosition);
|
||||||
|
ResultSet output = _dcd.getCompletions(importPaths, content, byteOffset);
|
||||||
switch(output.result) {
|
switch(output.result) {
|
||||||
//TODO: Show dialog
|
//TODO: Show dialog
|
||||||
case DCDResult.FAIL:
|
case DCDResult.FAIL:
|
||||||
|
@ -73,8 +78,7 @@ class DEditorTool : EditorTool
|
||||||
private:
|
private:
|
||||||
DCDInterface _dcd;
|
DCDInterface _dcd;
|
||||||
|
|
||||||
// TODO: non-ascii characters support
|
int caretPositionToByteOffset(string content, TextPosition caretPosition) {
|
||||||
int caretPositionToByteOffset(dstring content, TextPosition caretPosition) {
|
|
||||||
auto line = 0;
|
auto line = 0;
|
||||||
auto pos = 0;
|
auto pos = 0;
|
||||||
auto bytes = 0;
|
auto bytes = 0;
|
||||||
|
@ -92,7 +96,7 @@ private:
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextPosition byteOffsetToCaret(dstring content, int byteOffset) {
|
TextPosition byteOffsetToCaret(string content, int byteOffset) {
|
||||||
int bytes = 0;
|
int bytes = 0;
|
||||||
int line = 0;
|
int line = 0;
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
|
|
|
@ -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_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_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_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);
|
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();
|
||||||
|
|
|
@ -32,7 +32,8 @@ class DSourceEdit : SourceEdit {
|
||||||
setTokenHightlightColor(TokenCategory.Comment_Documentation, 0x206000);
|
setTokenHightlightColor(TokenCategory.Comment_Documentation, 0x206000);
|
||||||
//setTokenHightlightColor(TokenCategory.Identifier, 0x206000); // no colors
|
//setTokenHightlightColor(TokenCategory.Identifier, 0x206000); // no colors
|
||||||
MenuItem editPopupItem = new MenuItem(null);
|
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;
|
popupMenu = editPopupItem;
|
||||||
showIcons = true;
|
showIcons = true;
|
||||||
showFolding = true;
|
showFolding = true;
|
||||||
|
@ -50,8 +51,12 @@ class DSourceEdit : SourceEdit {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property bool isDSourceFile() {
|
||||||
|
return filename.endsWith(".d") || filename.endsWith(".dd") || filename.endsWith(".dh") || filename.endsWith(".ddoc");
|
||||||
|
}
|
||||||
|
|
||||||
void setHighlighter() {
|
void setHighlighter() {
|
||||||
if (filename.endsWith(".d") || filename.endsWith(".dd") || filename.endsWith(".dh") || filename.endsWith(".ddoc")) {
|
if (isDSourceFile) {
|
||||||
content.syntaxHighlighter = new SimpleDSyntaxHighlighter(filename);
|
content.syntaxHighlighter = new SimpleDSyntaxHighlighter(filename);
|
||||||
} else {
|
} else {
|
||||||
content.syntaxHighlighter = null;
|
content.syntaxHighlighter = null;
|
||||||
|
@ -61,7 +66,7 @@ class DSourceEdit : SourceEdit {
|
||||||
/// returns project import paths - if file from project is opened in current editor
|
/// returns project import paths - if file from project is opened in current editor
|
||||||
string[] importPaths() {
|
string[] importPaths() {
|
||||||
if (_projectSourceFile)
|
if (_projectSourceFile)
|
||||||
return _projectSourceFile.project.sourcePaths;
|
return _projectSourceFile.project.sourcePaths ~ _projectSourceFile.project.builderSourcePaths;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,6 +105,21 @@ class DSourceEdit : SourceEdit {
|
||||||
return super.handleAction(a);
|
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) {
|
void showCompletionPopup(dstring[] suggestions) {
|
||||||
|
|
||||||
if(suggestions.length == 0) {
|
if(suggestions.length == 0) {
|
||||||
|
|
|
@ -352,7 +352,7 @@ class IDEFrame : AppFrame {
|
||||||
editItem.add(ACTION_EDIT_COPY, ACTION_EDIT_PASTE,
|
editItem.add(ACTION_EDIT_COPY, ACTION_EDIT_PASTE,
|
||||||
ACTION_EDIT_CUT, ACTION_EDIT_UNDO, ACTION_EDIT_REDO);
|
ACTION_EDIT_CUT, ACTION_EDIT_UNDO, ACTION_EDIT_REDO);
|
||||||
MenuItem editItemAdvanced = new MenuItem(new Action(221, "MENU_EDIT_ADVANCED"));
|
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(editItemAdvanced);
|
||||||
|
|
||||||
editItem.add(ACTION_EDIT_PREFERENCES);
|
editItem.add(ACTION_EDIT_PREFERENCES);
|
||||||
|
|
Loading…
Reference in New Issue