Merge 8a632b3b96 into 1498ef1c1c
This commit is contained in:
commit
1c91c6efa7
35
README.md
35
README.md
|
|
@ -23,26 +23,29 @@ the issue.)
|
||||||
|
|
||||||
* Working:
|
* Working:
|
||||||
* Autocompletion of properties of built-in types such as int, float, double, etc.
|
* Autocompletion of properties of built-in types such as int, float, double, etc.
|
||||||
* Autocompletion of __traits, scope, and extern arguments
|
* Autocompletion of __traits, scope, and extern arguments.
|
||||||
* Autocompletion of enums
|
* Autocompletion of enums.
|
||||||
* Autocompletion of class, struct, and interface instances.
|
* Autocompletion of class, struct, and interface instances.
|
||||||
* Display of call tips for functions, constructors, and variables of function type
|
* Display of call tips for functions, constructors, and variables of function type.
|
||||||
* alias declarations
|
* *alias* declarations.
|
||||||
* Public imports
|
* Public imports.
|
||||||
* Finding the declaration location of a symbol at the cursor
|
* Finding the declaration location of a symbol at the cursor.
|
||||||
* *import* statement completions
|
* *import* statement completions.
|
||||||
* Display of documentation comments in function call tips
|
* Display of documentation comments in function call tips.
|
||||||
* *alias this*
|
* *alias this*.
|
||||||
* *auto* declarations (Mostly)
|
* *auto* declarations (mostly).
|
||||||
* *with* statements
|
* *with* statements.
|
||||||
* Simple UFCS suggestions for concrete types and fundamental types.
|
* Simple UFCS suggestions for concrete types and fundamental types.
|
||||||
|
* ImportC modules (if the environment variable `DMD` or the `dmd` found in the
|
||||||
|
`PATH`, resolves to a dmd compiler/wrapper that supports `-Hf`).
|
||||||
* Not working:
|
* Not working:
|
||||||
* UFCS completion for templates, literals, aliased types, UFCS function arguments, and '.' chaining with other UFCS functions.
|
* UFCS completion for templates, literals, aliased types, UFCS function arguments, and '.' chaining with other UFCS functions.
|
||||||
* UFCS calltips
|
* UFCS calltips.
|
||||||
* Autocompletion of declarations with template arguments (This will work to some extent, but it won't do things like replace T with int)
|
* Autocompletion of declarations with template arguments (This will work to some extent, but it won't do things like replace T with int).
|
||||||
* Determining the type of an enum member when no base type is specified, but the first member has an initializer
|
* Determining the type of an enum member when no base type is specified, but the first member has an initializer.
|
||||||
* auto functions (which can then propagate the failure to auto declarations)
|
* *auto* functions (which can then propagate the failure to auto declarations).
|
||||||
* That one feature that you *REALLY* needed
|
* *import* statement completion with ImportC modules.
|
||||||
|
* That one feature that you *REALLY* needed.
|
||||||
|
|
||||||
# Setup
|
# Setup
|
||||||
### General
|
### General
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,10 @@ struct ModuleCache
|
||||||
*/
|
*/
|
||||||
DSymbol* cacheModule(string location)
|
DSymbol* cacheModule(string location)
|
||||||
{
|
{
|
||||||
|
import std.file : tempDir;
|
||||||
|
import std.process : execute;
|
||||||
import std.stdio : File;
|
import std.stdio : File;
|
||||||
|
import std.uuid : randomUUID;
|
||||||
|
|
||||||
assert (location !is null);
|
assert (location !is null);
|
||||||
|
|
||||||
|
|
@ -162,7 +165,29 @@ struct ModuleCache
|
||||||
|
|
||||||
recursionGuard.insert(&cachedLocation.data[0]);
|
recursionGuard.insert(&cachedLocation.data[0]);
|
||||||
|
|
||||||
File f = File(cachedLocation);
|
string generatedHeaderFile;
|
||||||
|
scope (exit)
|
||||||
|
{
|
||||||
|
if (generatedHeaderFile.length && generatedHeaderFile.exists)
|
||||||
|
generatedHeaderFile.remove;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool isImportC = cachedLocation.extension.among(".c", ".h", ".i") > 0;
|
||||||
|
if (isImportC)
|
||||||
|
{
|
||||||
|
generatedHeaderFile = buildPath(tempDir, "dcd_" ~ randomUUID.toString ~ ".di");
|
||||||
|
const dmdResult = execute([dmd, "-o-", "-Hf" ~ generatedHeaderFile, cachedLocation]);
|
||||||
|
if (dmdResult.status != 0)
|
||||||
|
{
|
||||||
|
warningf(
|
||||||
|
"Generating .di file for ImportC file \"%s\" failed with status code %d: %s",
|
||||||
|
cachedLocation, dmdResult.status, dmdResult.output,
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
File f = File(isImportC ? generatedHeaderFile : cachedLocation);
|
||||||
immutable fileSize = cast(size_t) f.size;
|
immutable fileSize = cast(size_t) f.size;
|
||||||
if (fileSize == 0)
|
if (fileSize == 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -301,13 +326,18 @@ struct ModuleCache
|
||||||
// no exact matches and no .di/package.d matches either
|
// no exact matches and no .di/package.d matches either
|
||||||
else if (!alternative.length)
|
else if (!alternative.length)
|
||||||
{
|
{
|
||||||
string dotDi = buildPath(path, moduleName) ~ ".di";
|
string withoutSuffix = buildPath(path, moduleName);
|
||||||
string dotD = dotDi[0 .. $ - 1];
|
string dotD = withoutSuffix ~ ".d";
|
||||||
string withoutSuffix = dotDi[0 .. $ - 3];
|
string dotDi = dotD ~ "i";
|
||||||
|
string dotC = withoutSuffix ~ ".c";
|
||||||
|
string dotH = withoutSuffix ~ ".h";
|
||||||
|
string dotI = withoutSuffix ~ ".i";
|
||||||
if (existsAnd!isFile(dotD))
|
if (existsAnd!isFile(dotD))
|
||||||
return istring(dotD); // return early for exactly matching .d files
|
return istring(dotD); // return early for exactly matching .d files
|
||||||
else if (existsAnd!isFile(dotDi))
|
else if (existsAnd!isFile(dotDi)) alternative = dotDi;
|
||||||
alternative = dotDi;
|
else if (existsAnd!isFile(dotC)) alternative = dotC;
|
||||||
|
else if (existsAnd!isFile(dotH)) alternative = dotH;
|
||||||
|
else if (existsAnd!isFile(dotI)) alternative = dotI;
|
||||||
else if (existsAnd!isDir(withoutSuffix))
|
else if (existsAnd!isDir(withoutSuffix))
|
||||||
{
|
{
|
||||||
string packagePath = buildPath(withoutSuffix, "package.di");
|
string packagePath = buildPath(withoutSuffix, "package.di");
|
||||||
|
|
@ -402,7 +432,7 @@ private:
|
||||||
{
|
{
|
||||||
if (f.name.existsAnd!isFile)
|
if (f.name.existsAnd!isFile)
|
||||||
{
|
{
|
||||||
if (!f.name.extension.among(".d", ".di") || f.name.baseName.startsWith(".#"))
|
if (!f.name.extension.among(".d", ".di", ".c", ".h", ".i") || f.name.baseName.startsWith(".#"))
|
||||||
continue;
|
continue;
|
||||||
cacheModule(f.name);
|
cacheModule(f.name);
|
||||||
}
|
}
|
||||||
|
|
@ -522,3 +552,13 @@ else version (Posix)
|
||||||
assert(!existsAnd!isFile(`/bin`));
|
assert(!existsAnd!isFile(`/bin`));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private @safe
|
||||||
|
string dmd()
|
||||||
|
{
|
||||||
|
import std.process : environment;
|
||||||
|
|
||||||
|
if ("DMD" in environment)
|
||||||
|
return environment["DMD"];
|
||||||
|
return "dmd";
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue