rwols created this revision.
Enhances CompletionItemsCollector in such a way that snippet
completions are presented to the client.
This is a work-in-progress. It currently works in Sublime Text 3 using the new
"LSP" plugin. In VSCode, the snippets are inserted into the buffer as plaintext
without any processing (bug). Untested in Atom.
See:
https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#completion-request
See:
https://github.com/Microsoft/vscode/blob/master/src/vs/editor/contrib/snippet/browser/snippet.md
https://reviews.llvm.org/D37101
Files:
clangd/ClangdUnit.cpp
clangd/Protocol.cpp
Index: clangd/Protocol.cpp
===================================================================
--- clangd/Protocol.cpp
+++ clangd/Protocol.cpp
@@ -724,8 +724,8 @@
if (!CI.insertText.empty())
Os << R"("insertText":")" << llvm::yaml::escape(CI.insertText) << R"(",)";
if (CI.insertTextFormat != InsertTextFormat::Missing) {
- Os << R"("insertTextFormat":")" << static_cast<int>(CI.insertTextFormat)
- << R"(",)";
+ Os << R"("insertTextFormat":)" << static_cast<int>(CI.insertTextFormat)
+ << R"(,)";
}
if (CI.textEdit)
Os << R"("textEdit":)" << TextEdit::unparse(*CI.textEdit) << ',';
Index: clangd/ClangdUnit.cpp
===================================================================
--- clangd/ClangdUnit.cpp
+++ clangd/ClangdUnit.cpp
@@ -288,45 +288,180 @@
void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
CodeCompletionResult *Results,
unsigned NumResults) override {
+ // Sort the completions by their priority. A higher priority should come
+ // earlier in the sequence.
+ std::stable_sort(Results, Results + NumResults,
+ [](const CodeCompletionResult &lhs,
+ const CodeCompletionResult &rhs) -> bool {
+ return lhs.Priority > rhs.Priority;
+ });
for (unsigned I = 0; I != NumResults; ++I) {
- CodeCompletionResult &Result = Results[I];
- CodeCompletionString *CCS = Result.CreateCodeCompletionString(
- S, Context, *Allocator, CCTUInfo,
- CodeCompleteOpts.IncludeBriefComments);
- if (CCS) {
+ if (Results[I].Availability == CXAvailability_NotAvailable ||
+ Results[I].Availability == CXAvailability_NotAccessible) {
+ // A private member variable outside of the class, for example.
+ continue;
+ } else {
CompletionItem Item;
- for (CodeCompletionString::Chunk C : *CCS) {
- switch (C.Kind) {
- case CodeCompletionString::CK_ResultType:
- Item.detail = C.Text;
- break;
- case CodeCompletionString::CK_Optional:
- break;
- default:
- Item.label += C.Text;
- break;
- }
- }
- assert(CCS->getTypedText());
- Item.kind = getKind(Result.CursorKind);
- // Priority is a 16-bit integer, hence at most 5 digits.
- assert(CCS->getPriority() < 99999 && "Expecting code completion result "
- "priority to have at most "
- "5-digits");
- llvm::raw_string_ostream(Item.sortText)
- << llvm::format("%05d%s", CCS->getPriority(), CCS->getTypedText());
- Item.insertText = Item.filterText = CCS->getTypedText();
- if (CCS->getBriefComment())
- Item.documentation = CCS->getBriefComment();
+ this->ProcessCodeCompleteResult(S, Context, Results[I], Item);
Items->push_back(std::move(Item));
}
}
}
GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }
CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
-};
+
+private:
+ void ProcessCodeCompleteResult(Sema &S, CodeCompletionContext Context,
+ CodeCompletionResult &Result,
+ CompletionItem &Item) {
+ unsigned ArgCount = 0;
+
+ // Fill in the label, detail, documentation and insertText fields of the
+ // CompletionItem.
+ switch (Result.Kind) {
+ case CodeCompletionResult::RK_Declaration: {
+ auto Completion = Result.CreateCodeCompletionString(
+ S, Context, *Allocator, CCTUInfo,
+ CodeCompleteOpts.IncludeBriefComments);
+ if (!Completion) {
+ Item.label = Result.Declaration->getNameAsString();
+ } else {
+ ProcessCodeCompleteString(*Completion, ArgCount, Item);
+ }
+ break;
+ }
+ case CodeCompletionResult::RK_Keyword:
+ Item.label = Result.Keyword;
+ break;
+ case CodeCompletionResult::RK_Macro: {
+ auto Completion = Result.CreateCodeCompletionString(
+ S, Context, *Allocator, CCTUInfo,
+ CodeCompleteOpts.IncludeBriefComments);
+ if (!Completion) {
+ Item.label = Result.Macro->getName().str();
+ } else {
+ ProcessCodeCompleteString(*Completion, ArgCount, Item);
+ }
+ break;
+ }
+ case CodeCompletionResult::RK_Pattern: {
+ assert(Result.Pattern && "we should have a code completion string here");
+ ProcessCodeCompleteString(*Result.Pattern, ArgCount, Item);
+ break;
+ }
+ default:
+ llvm_unreachable("Unknown CodeCompletionResult kind");
+ }
+
+ // Fill in the kind field of the CompletionItem.
+ Item.kind = getKind(Result.CursorKind);
+
+ // Always a snippet for now.
+ Item.insertTextFormat = InsertTextFormat::Snippet;
+ }
+
+ void ProcessCodeCompleteString(const CodeCompletionString &CCS,
+ unsigned &ArgCount,
+ CompletionItem &Item) const {
+ for (unsigned j = 0; j < CCS.getAnnotationCount(); ++j) {
+ // Things like __attribute__((nonnull(1,3))). Stash this information in
+ // the documentation field.
+ Item.documentation += "[" + std::string(CCS.getAnnotation(j)) + "]";
+ if (j != CCS.getAnnotationCount() - 1)
+ Item.documentation += ' ';
+ }
+ for (const auto &Chunk : CCS) {
+ switch (Chunk.Kind) {
+ case CodeCompletionString::CK_TypedText:
+ // The piece of text that the user is expected to type to match
+ // the code-completion string, typically a keyword or the name of
+ // a declarator or macro.
+ Item.label += Chunk.Text;
+ Item.insertText += Chunk.Text;
+ break;
+ case CodeCompletionString::CK_Text:
+ // A piece of text that should be placed in the buffer,
+ // e.g., parentheses or a comma in a function call.
+ Item.label += Chunk.Text;
+ Item.insertText += Chunk.Text;
+ break;
+ case CodeCompletionString::CK_Optional:
+ // A code completion string that is entirely optional.
+ // For example, an optional code completion string that
+ // describes the default arguments in a function call.
+ break;
+ case CodeCompletionString::CK_Placeholder:
+ // A string that acts as a placeholder for, e.g., a function call
+ // argument.
+ ++ArgCount;
+ Item.insertText +=
+ "${" + std::to_string(ArgCount) + ":" + Chunk.Text + "}";
+ Item.label += Chunk.Text;
+ break;
+ case CodeCompletionString::CK_Informative:
+ // A piece of text that describes something about the result
+ // but should not be inserted into the buffer.
+ Item.documentation += "[" + std::string(Chunk.Text) + "] ";
+ break;
+ case CodeCompletionString::CK_ResultType:
+ // A piece of text that describes the type of an entity or,
+ // for functions and methods, the return type.
+ Item.detail += Chunk.Text;
+ break;
+ case CodeCompletionString::CK_CurrentParameter:
+ // A piece of text that describes the parameter that corresponds
+ // to the code-completion location within a function call, message
+ // send, macro invocation, etc.
+ ++ArgCount;
+ Item.insertText +=
+ "${" + std::to_string(ArgCount) + ":" + Chunk.Text + "}";
+ Item.label += Chunk.Text;
+ break;
+ case CodeCompletionString::CK_LeftParen:
+ // A left parenthesis ('(').
+ case CodeCompletionString::CK_RightParen:
+ // A right parenthesis (')').
+ case CodeCompletionString::CK_LeftBracket:
+ // A left bracket ('[').
+ case CodeCompletionString::CK_RightBracket:
+ // A right bracket (']').
+ case CodeCompletionString::CK_LeftBrace:
+ // A left brace ('{').
+ case CodeCompletionString::CK_RightBrace:
+ // A right brace ('}').
+ case CodeCompletionString::CK_LeftAngle:
+ // A left angle bracket ('<').
+ case CodeCompletionString::CK_RightAngle:
+ // A right angle bracket ('>').
+ case CodeCompletionString::CK_Comma:
+ // A comma separator (',').
+ case CodeCompletionString::CK_Colon:
+ // A colon (':').
+ case CodeCompletionString::CK_SemiColon:
+ // A semicolon (';').
+ case CodeCompletionString::CK_Equal:
+ // An '=' sign.
+ case CodeCompletionString::CK_HorizontalSpace:
+ // Horizontal whitespace (' ').
+ case CodeCompletionString::CK_VerticalSpace:
+ // Vertical whitespace ('\n' or '\r\n', depending on the
+ // platform).
+ Item.insertText += Chunk.Text;
+ Item.label += Chunk.Text;
+ break;
+ default:
+ llvm_unreachable("Unknown CodeCompletionString chunk type!");
+ }
+ }
+
+ // Add documentation (if there is any).
+ if (CCS.getBriefComment() != nullptr) {
+ Item.documentation += CCS.getBriefComment();
+ }
+ }
+}; // CompletionItemsCollector
} // namespace
std::vector<CompletionItem>
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits