This commit is contained in:
Jonas Meeuws 2025-10-27 13:40:26 +00:00 committed by GitHub
commit 1c91c6efa7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 66 additions and 23 deletions

View File

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

View File

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