Skip to content

Commit

Permalink
compiler import paths detection - implement #194
Browse files Browse the repository at this point in the history
  • Loading branch information
buggins committed Sep 26, 2017
1 parent 37b7eec commit 9c6a513
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 94 deletions.
49 changes: 0 additions & 49 deletions src/dlangide/builders/builder.d
Original file line number Diff line number Diff line change
Expand Up @@ -171,52 +171,3 @@ class Builder : BackgroundOperationWatcher {
}
}

string[] splitByLines(string s) {
string[] res;
int start = 0;
for(int i = 0; i <= s.length; i++) {
if (i == s.length) {
if (start < i)
res ~= s[start .. i];
break;
}
if (s[i] == '\r' || s[i] == '\n') {
if (start < i)
res ~= s[start .. i];
start = i + 1;
}
}
return res;
}

string[] detectImportPathsForCompiler(string compiler) {
string[] res;
import std.process : executeShell;
import std.string : startsWith, indexOf;
import std.path : buildNormalizedPath;
import std.file : write, remove;
import dlangui.core.files;
try {
string sourcefilename = appDataPath(".dlangide") ~ PATH_DELIMITER ~ "tmp_dummy_file_to_get_import_paths.d";
write(sourcefilename, "import module_that_does_not_exist;\n");
auto ls = executeShell("\"" ~ compiler ~ "\" \"" ~ sourcefilename ~ "\"");
remove(sourcefilename);
string s = ls.output;
string[] lines = splitByLines(s);
debug Log.d("compiler output:\n", s);
foreach(line; lines) {
if (line.startsWith("import path[")) {
auto p = line.indexOf("] = ");
if (p > 0) {
line = line[p + 4 .. $];
string path = line.buildNormalizedPath;
debug Log.d("import path found: `", line, "`");
res ~= line;
}
}
}
return res;
} catch (Exception e) {
return null;
}
}
6 changes: 3 additions & 3 deletions src/dlangide/tools/d/deditortool.d
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class DEditorTool : EditorTool
DCDTask _getDocCommentsTask;
override void getDocComments(DSourceEdit editor, TextPosition caretPosition, void delegate(string[]) callback) {
cancelGetDocComments();
string[] importPaths = editor.importPaths();
string[] importPaths = editor.importPaths(_frame.settings);
string content = toUTF8(editor.text);
auto byteOffset = caretPositionToByteOffset(content, caretPosition);
if (!isAtWord(content, byteOffset))
Expand Down Expand Up @@ -88,7 +88,7 @@ class DEditorTool : EditorTool
DCDTask _goToDefinitionTask;
override void goToDefinition(DSourceEdit editor, TextPosition caretPosition) {
cancelGoToDefinition();
string[] importPaths = editor.importPaths();
string[] importPaths = editor.importPaths(_frame.settings);
string content = toUTF8(editor.text);
auto byteOffset = caretPositionToByteOffset(content, caretPosition);

Expand Down Expand Up @@ -129,7 +129,7 @@ class DEditorTool : EditorTool
DCDTask _getCompletionsTask;
override void getCompletions(DSourceEdit editor, TextPosition caretPosition, void delegate(dstring[] completions, string[] icons, CompletionTypes type) callback) {
cancelGetCompletions();
string[] importPaths = editor.importPaths();
string[] importPaths = editor.importPaths(_frame.settings);

string content = toUTF8(editor.text);
auto byteOffset = caretPositionToByteOffset(content, caretPosition);
Expand Down
4 changes: 2 additions & 2 deletions src/dlangide/ui/dsourceedit.d
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,9 @@ class DSourceEdit : SourceEdit, EditableContentMarksChangeListener {
}

/// returns project import paths - if file from project is opened in current editor
string[] importPaths() {
string[] importPaths(IDESettings ideSettings) {
if (_projectSourceFile)
return _projectSourceFile.project.importPaths;
return _projectSourceFile.project.importPaths(ideSettings);
return null;
}

Expand Down
14 changes: 7 additions & 7 deletions src/dlangide/ui/frame.d
Original file line number Diff line number Diff line change
Expand Up @@ -698,20 +698,20 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
_logPanel.appendText(null, dubPath ? ("dub path: "d ~ toUTF32(dubPath) ~ "\n"d) : ("dub is not found! cannot build projects without DUB\n"d));
_logPanel.appendText(null, rdmdPath ? ("rdmd path: "d ~ toUTF32(rdmdPath) ~ "\n"d) : ("rdmd is not found!\n"d));
_logPanel.appendText(null, dmdPath ? ("dmd path: "d ~ toUTF32(dmdPath) ~ "\n"d) : ("dmd compiler is not found!\n"d));
dumpCompilerPath("DMD", dmdPath);
dumpCompilerPath("dmd", dmdPath);
_logPanel.appendText(null, ldcPath ? ("ldc path: "d ~ toUTF32(ldcPath) ~ "\n"d) : ("ldc compiler is not found!\n"d));
dumpCompilerPath("LDC", ldcPath);
dumpCompilerPath("ldc", ldcPath);
_logPanel.appendText(null, gdcPath ? ("gdc path: "d ~ toUTF32(gdcPath) ~ "\n"d) : ("gdc compiler is not found!\n"d));
dumpCompilerPath("GDC", gdcPath);
dumpCompilerPath("gdc", gdcPath);
}
private void dumpCompilerPath(dstring compilerName, string compiler) {
private void dumpCompilerPath(string compilerName, string compiler) {
if (!compiler)
return;
if (compiler) {
string[] imports = detectImportPathsForCompiler(compiler);
string[] imports = compilerImportPathsCache.getImportPathsFor(compilerName);
if (imports.length > 0) {
Log.d(compilerName, " imports:", imports);
_logPanel.appendText(null, compilerName ~ " imports:\n"d);
_logPanel.appendText(null, to!dstring(compilerName) ~ " imports:\n"d);
foreach(s; imports)
_logPanel.appendText(null, " "d ~ to!dstring(s) ~ "\n"d);
}
Expand Down Expand Up @@ -1601,7 +1601,7 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
}

public void warmUpImportPaths(Project project) {
dcdInterface.warmUp(project.importPaths);
dcdInterface.warmUp(project.importPaths(_settings));
}

void restoreListOfOpenedFiles() {
Expand Down
139 changes: 106 additions & 33 deletions src/dlangide/workspace/project.d
Original file line number Diff line number Diff line change
Expand Up @@ -305,29 +305,6 @@ class WorkspaceItem {
}
}

/// detect DMD source paths
string[] dmdSourcePaths() {
string[] res;

if(!includePath.empty){
res ~= includePath;
}

version(Windows) {
import dlangui.core.files;
string dmdPath = findExecutablePath("dmd");
if (dmdPath) {
string dmdDir = buildNormalizedPath(dirName(dmdPath), "..", "..", "src");
res ~= absolutePath(buildNormalizedPath(dmdDir, "druntime", "import"));
res ~= absolutePath(buildNormalizedPath(dmdDir, "phobos"));
}
} else {
res ~= "/usr/include/dmd/druntime/import";
res ~= "/usr/include/dmd/phobos";
}
return res;
}

/// Stores info about project configuration
struct ProjectConfiguration {
/// name used to build the project
Expand Down Expand Up @@ -384,6 +361,7 @@ struct ProjectConfiguration {

/// DLANGIDE D project
class Project : WorkspaceItem {
import dlangide.workspace.idesettings : IDESettings;
protected Workspace _workspace;
protected bool _opened;
protected ProjectFolder _items;
Expand All @@ -397,7 +375,6 @@ class Project : WorkspaceItem {
protected string _dependencyVersion;

protected string[] _sourcePaths;
protected string[] _builderSourcePaths;
protected ProjectConfiguration[] _configurations;
protected ProjectConfiguration _projectConfiguration = ProjectConfiguration.DEFAULT;

Expand Down Expand Up @@ -529,12 +506,12 @@ class Project : WorkspaceItem {

/// returns project's own source paths
@property string[] sourcePaths() { return _sourcePaths; }
/// returns project's own source paths
@property string[] builderSourcePaths() {
if (!_builderSourcePaths) {
_builderSourcePaths = dmdSourcePaths();
}
return _builderSourcePaths;
/// returns project's current toolchain import paths
string[] builderSourcePaths(IDESettings ideSettings) {
string compilerName = settings.getToolchain(ideSettings);
if (!compilerName)
compilerName = "default";
return compilerImportPathsCache.getImportPathsFor(compilerName);
}

/// returns first source folder for project or null if not found
Expand All @@ -556,10 +533,10 @@ class Project : WorkspaceItem {
dst ~= item;
}
}
@property string[] importPaths() {
@property string[] importPaths(IDESettings ideSettings) {
string[] res;
addUnique(res, sourcePaths);
addUnique(res, builderSourcePaths);
addUnique(res, builderSourcePaths(ideSettings));
foreach(dep; _dependencies) {
addUnique(res, dep.sourcePaths);
}
Expand Down Expand Up @@ -805,7 +782,7 @@ class Project : WorkspaceItem {
findMainSourceFile();

Log.i("Project source paths: ", sourcePaths);
Log.i("Builder source paths: ", builderSourcePaths);
//Log.i("Builder source paths: ", builderSourcePaths(_settings));
if (!_isDependency)
loadSelections();

Expand Down Expand Up @@ -1003,3 +980,99 @@ class EditorBookmark {
int line;
string projectName;
}


string[] splitByLines(string s) {
string[] res;
int start = 0;
for(int i = 0; i <= s.length; i++) {
if (i == s.length) {
if (start < i)
res ~= s[start .. i];
break;
}
if (s[i] == '\r' || s[i] == '\n') {
if (start < i)
res ~= s[start .. i];
start = i + 1;
}
}
return res;
}

struct CompilerImportPathsCache {

private static class Entry {
string[] list;
}
private Entry[string] _cache;

string[] getImportPathsFor(string compiler) {
import dlangui.core.files : findExecutablePath;
if (!compiler.length)
return [];
if (auto p = compiler in _cache) {
// found in cache
return p.list;
}
Log.d("Searching for compiler path: ", compiler);
import std.path : isAbsolute;
string compilerPath = compiler;
if (compiler == "default") {
// try to autodetect default compiler
compilerPath = findExecutablePath("dmd");
if (!compilerPath)
compilerPath = findExecutablePath("ldc");
if (!compilerPath)
compilerPath = findExecutablePath("gdc");
} else if (compilerPath && !compilerPath.isAbsolute)
compilerPath = findExecutablePath(compiler);
string[] res;
if (compilerPath)
res = detectImportPathsForCompiler(compilerPath);
else
Log.w("Compiler executable not found for `", compiler, "`");
Entry newItem = new Entry();
newItem.list = res;
_cache[compiler] = newItem;
return res;
}
}

__gshared CompilerImportPathsCache compilerImportPathsCache;

string[] detectImportPathsForCompiler(string compiler) {
string[] res;
import std.process : pipeProcess, Redirect, wait;
import std.string : startsWith, indexOf;
import std.path : buildNormalizedPath;
import std.file : write, remove;
import dlangui.core.files;
try {
string sourcefilename = appDataPath(".dlangide") ~ PATH_DELIMITER ~ "tmp_dummy_file_to_get_import_paths.d";
write(sourcefilename, "import module_that_does_not_exist;\n");
auto pipes = pipeProcess([compiler, sourcefilename], Redirect.stdin | Redirect.stdout | Redirect.stderrToStdout, null, Config.suppressConsole);
char[4096] buffer;
char[] s = pipes.stdout.rawRead(buffer);
wait(pipes.pid);
//auto ls = execute([compiler, sourcefilename]);
remove(sourcefilename);
//string s = ls.output;
string[] lines = splitByLines(cast(string)s);
debug Log.d("compiler output:\n", s);
foreach(line; lines) {
if (line.startsWith("import path[")) {
auto p = line.indexOf("] = ");
if (p > 0) {
line = line[p + 4 .. $];
string path = line.buildNormalizedPath;
debug Log.d("import path found: `", path, "`");
res ~= path;
}
}
}
return res;
} catch (Exception e) {
return null;
}
}

0 comments on commit 9c6a513

Please sign in to comment.