summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-language-server.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2022-07-01 15:09:24 -0700
committerGitHub <noreply@github.com>2022-07-01 15:09:24 -0700
commit0bf899a5f8110fbea97272bdda03b68b91745e51 (patch)
tree6e6a0e0210c84e911e563fe3ca6ca4ec4c2dbf4d /source/slang/slang-language-server.cpp
parentb0ea5ed4da709312910898fa03b4dafc7a27e358 (diff)
Language server: auto completion of `import` file and directories. (#2312)
* Language server: auto completion of `import` file and directories. * Completion of include path. * Improvements. Co-authored-by: Yong He <yhe@nvidia.com>
Diffstat (limited to 'source/slang/slang-language-server.cpp')
-rw-r--r--source/slang/slang-language-server.cpp127
1 files changed, 98 insertions, 29 deletions
diff --git a/source/slang/slang-language-server.cpp b/source/slang/slang-language-server.cpp
index 7dc2f6dcc..673b91593 100644
--- a/source/slang/slang-language-server.cpp
+++ b/source/slang/slang-language-server.cpp
@@ -123,6 +123,8 @@ SlangResult LanguageServer::parseNextMessage()
result.capabilities.completionProvider.triggerCharacters.add(".");
result.capabilities.completionProvider.triggerCharacters.add(":");
result.capabilities.completionProvider.triggerCharacters.add("[");
+ result.capabilities.completionProvider.triggerCharacters.add("\"");
+ result.capabilities.completionProvider.triggerCharacters.add("/");
result.capabilities.completionProvider.resolveProvider = true;
result.capabilities.completionProvider.workDoneToken = "";
result.capabilities.semanticTokensProvider.full = true;
@@ -347,6 +349,26 @@ void appendDefinitionLocation(StringBuilder& sb, Workspace* workspace, const Hum
sb << "Defined in " << pathSlice << "(" << loc.line << ")\n";
}
+HumaneSourceLoc getModuleLoc(SourceManager* manager, ModuleDecl* moduleDecl)
+{
+ if (moduleDecl)
+ {
+ if (moduleDecl->members.getCount() &&
+ moduleDecl->members[0])
+ {
+ auto loc = moduleDecl->members[0]->loc;
+ if (loc.isValid())
+ {
+ auto location = manager->getHumaneLoc(loc, SourceLocType::Actual);
+ location.line = 1;
+ location.column = 1;
+ return location;
+ }
+ }
+ }
+ return HumaneSourceLoc();
+}
+
SlangResult LanguageServer::hover(
const LanguageServerProtocol::HoverParams& args, const JSONValue& responseId)
{
@@ -429,6 +451,27 @@ SlangResult LanguageServer::hover(
LookupResultItem& item = overloadedExpr->lookupResult2.item;
fillDeclRefHoverInfo(item.declRef);
}
+ else if (auto importDecl = as<ImportDecl>(leafNode))
+ {
+ auto moduleLoc = getModuleLoc(version->linkage->getSourceManager(), importDecl->importedModuleDecl);
+ if (moduleLoc.pathInfo.hasFoundPath())
+ {
+ String path = moduleLoc.pathInfo.foundPath;
+ Path::getCanonical(path, path);
+ sb << path;
+ auto humaneLoc = version->linkage->getSourceManager()->getHumaneLoc(
+ importDecl->startLoc, SourceLocType::Actual);
+ Index utf16Line, utf16Col;
+ doc->oneBasedUTF8LocToZeroBasedUTF16Loc(humaneLoc.line, humaneLoc.column, utf16Line, utf16Col);
+ hover.range.start.line = (int)utf16Line;
+ hover.range.start.character = (int)utf16Col;
+ humaneLoc = version->linkage->getSourceManager()->getHumaneLoc(
+ importDecl->endLoc, SourceLocType::Actual);
+ doc->oneBasedUTF8LocToZeroBasedUTF16Loc(humaneLoc.line, humaneLoc.column, utf16Line, utf16Col);
+ hover.range.end.line = (int)utf16Line;
+ hover.range.end.character = (int)utf16Col;
+ }
+ }
else if (auto decl = as<Decl>(leafNode))
{
fillDeclRefHoverInfo(DeclRef<Decl>(decl, nullptr));
@@ -529,18 +572,10 @@ SlangResult LanguageServer::gotoDefinition(
}
else if (auto importDecl = as<ImportDecl>(leafNode))
{
- if (importDecl->importedModuleDecl)
+ auto location = getModuleLoc(version->linkage->getSourceManager(), importDecl->importedModuleDecl);
+ if (location.pathInfo.hasFoundPath())
{
- if (importDecl->importedModuleDecl->members.getCount() &&
- importDecl->importedModuleDecl->members[0])
- {
- auto loc = importDecl->importedModuleDecl->members[0]->loc;
- if (loc.isValid())
- {
- auto location = version->linkage->getSourceManager()->getHumaneLoc(loc, SourceLocType::Actual);
- locations.add(LocationResult{location, 0});
- }
- }
+ locations.add(LocationResult{ location, 0 });
}
}
if (locations.getCount() == 0)
@@ -630,38 +665,58 @@ SlangResult LanguageServer::completion(
return SLANG_OK;
}
- // Insert a completion request token at cursor position.
- auto originalText = doc->getText();
- StringBuilder newText;
- newText << originalText.getUnownedSlice().head(cursorOffset + 1) << "#?"
- << originalText.getUnownedSlice().tail(cursorOffset + 1);
- doc->setText(newText.ProduceString());
- auto restoreDocText = makeDeferred([&]() { doc->setText(originalText); });
-
// Always create a new workspace version for the completion request since we
// will use a modified source.
auto version = m_workspace->createVersionForCompletion();
auto moduleName = getMangledNameFromNameString(canonicalPath.getUnownedSlice());
version->linkage->contentAssistInfo.cursorLine = utf8Line;
version->linkage->contentAssistInfo.cursorCol = utf8Col;
- Module* parsedModule = version->getOrLoadModule(canonicalPath);
- if (!parsedModule)
- {
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
- }
-
Slang::CompletionContext context;
context.server = this;
context.cursorOffset = cursorOffset;
context.version = version;
context.doc = doc.Ptr();
- context.parsedModule = parsedModule;
context.responseId = responseId;
context.canonicalPath = canonicalPath.getUnownedSlice();
context.line = utf8Line;
context.col = utf8Col;
context.commitCharacterBehavior = m_commitCharacterBehavior;
+
+ if (SLANG_SUCCEEDED(context.tryCompleteInclude()))
+ {
+ return SLANG_OK;
+ }
+ if (SLANG_SUCCEEDED(context.tryCompleteImport()))
+ {
+ return SLANG_OK;
+ }
+
+ if (args.context.triggerKind ==
+ LanguageServerProtocol::kCompletionTriggerKindTriggerCharacter &&
+ (args.context.triggerCharacter == "\"" || args.context.triggerCharacter == "/"))
+ {
+ // Trigger characters '"' and '/' are for include only.
+ m_connection->sendResult(NullResponse::get(), responseId);
+ return SLANG_OK;
+ }
+
+
+ // Insert a completion request token at cursor position.
+ auto originalText = doc->getText();
+ StringBuilder newText;
+ newText << originalText.getUnownedSlice().head(cursorOffset + 1) << "#?"
+ << originalText.getUnownedSlice().tail(cursorOffset + 1);
+ doc->setText(newText.ProduceString());
+ auto restoreDocText = makeDeferred([&]() { doc->setText(originalText); });
+
+ Module* parsedModule = version->getOrLoadModule(canonicalPath);
+ if (!parsedModule)
+ {
+ m_connection->sendResult(NullResponse::get(), responseId);
+ return SLANG_OK;
+ }
+
+ context.parsedModule = parsedModule;
if (SLANG_SUCCEEDED(context.tryCompleteAttributes()))
{
return SLANG_OK;
@@ -689,8 +744,19 @@ SlangResult LanguageServer::completion(
}
SlangResult LanguageServer::completionResolve(
- const LanguageServerProtocol::CompletionItem& args, const JSONValue& responseId)
+ const LanguageServerProtocol::CompletionItem& args, const LanguageServerProtocol::TextEditCompletionItem& editItem, const JSONValue& responseId)
{
+ if (args.data.getLength() == 0)
+ {
+ if (editItem.textEdit.newText.getLength())
+ {
+ m_connection->sendResult(&editItem, responseId);
+ return SLANG_OK;
+ }
+ m_connection->sendResult(&args, responseId);
+ return SLANG_OK;
+ }
+
LanguageServerProtocol::CompletionItem resolvedItem = args;
int itemId = StringToInt(args.data);
auto version = m_workspace->getCurrentCompletionVersion();
@@ -1455,6 +1521,9 @@ SlangResult LanguageServer::queueJSONCall(JSONRPCCall call)
Slang::LanguageServerProtocol::CompletionItem args;
SLANG_RETURN_ON_FAIL(m_connection->toNativeArgsOrSendError(call.params, &args, call.id));
cmd.completionResolveArgs = args;
+ Slang::LanguageServerProtocol::TextEditCompletionItem editArgs;
+ SLANG_RETURN_ON_FAIL(m_connection->toNativeArgsOrSendError(call.params, &editArgs, call.id));
+ cmd.textEditCompletionResolveArgs = editArgs;
}
else if (call.method == DocumentSymbolParams::methodName)
{
@@ -1541,7 +1610,7 @@ SlangResult LanguageServer::runCommand(Command& call)
}
else if (call.method == "completionItem/resolve")
{
- return completionResolve(call.completionResolveArgs.get(), call.id);
+ return completionResolve(call.completionResolveArgs.get(), call.textEditCompletionResolveArgs.get(), call.id);
}
else if (call.method == DocumentSymbolParams::methodName)
{