Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 19 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,29 @@ the issue.)

* Working:
* Autocompletion of properties of built-in types such as int, float, double, etc.
* Autocompletion of __traits, scope, and extern arguments
* Autocompletion of enums
* Autocompletion of __traits, scope, and extern arguments.
* Autocompletion of enums.
* Autocompletion of class, struct, and interface instances.
* Display of call tips for functions, constructors, and variables of function type
* alias declarations
* Public imports
* Finding the declaration location of a symbol at the cursor
* *import* statement completions
* Display of documentation comments in function call tips
* *alias this*
* *auto* declarations (Mostly)
* *with* statements
* Display of call tips for functions, constructors, and variables of function type.
* *alias* declarations.
* Public imports.
* Finding the declaration location of a symbol at the cursor.
* *import* statement completions.
* Display of documentation comments in function call tips.
* *alias this*.
* *auto* declarations (mostly).
* *with* statements.
* 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:
* UFCS completion for templates, literals, aliased types, UFCS function arguments, and '.' chaining with other UFCS functions.
* 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)
* 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)
* That one feature that you *REALLY* needed
* 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).
* 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).
* *import* statement completion with ImportC modules.
* That one feature that you *REALLY* needed.

# Setup
### General
Expand Down
54 changes: 47 additions & 7 deletions dsymbol/src/dsymbol/modulecache.d
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,10 @@ struct ModuleCache
*/
DSymbol* cacheModule(string location)
{
import std.file : tempDir;
import std.process : execute;
import std.stdio : File;
import std.uuid : randomUUID;

assert (location !is null);

Expand All @@ -162,7 +165,29 @@ struct ModuleCache

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;
if (fileSize == 0)
return null;
Expand Down Expand Up @@ -301,13 +326,18 @@ struct ModuleCache
// no exact matches and no .di/package.d matches either
else if (!alternative.length)
{
string dotDi = buildPath(path, moduleName) ~ ".di";
string dotD = dotDi[0 .. $ - 1];
string withoutSuffix = dotDi[0 .. $ - 3];
string withoutSuffix = buildPath(path, moduleName);
string dotD = withoutSuffix ~ ".d";
string dotDi = dotD ~ "i";
string dotC = withoutSuffix ~ ".c";
string dotH = withoutSuffix ~ ".h";
string dotI = withoutSuffix ~ ".i";
if (existsAnd!isFile(dotD))
return istring(dotD); // return early for exactly matching .d files
else if (existsAnd!isFile(dotDi))
alternative = dotDi;
else if (existsAnd!isFile(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))
{
string packagePath = buildPath(withoutSuffix, "package.di");
Expand Down Expand Up @@ -402,7 +432,7 @@ private:
{
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;
cacheModule(f.name);
}
Expand Down Expand Up @@ -522,3 +552,13 @@ else version (Posix)
assert(!existsAnd!isFile(`/bin`));
}
}

private @safe
string dmd()
{
import std.process : environment;

if ("DMD" in environment)
return environment["DMD"];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs to be documented in the README or other places where this might be relevant

return "dmd";
}
Loading