void print_completion_string(CXCompletionString completion_string, FILE *file) { int I, N; N = clang_getNumCompletionChunks(completion_string); for (I = 0; I != N; ++I) { CXString text; const char *cstr; enum CXCompletionChunkKind Kind = clang_getCompletionChunkKind(completion_string, I); if (Kind == CXCompletionChunk_Optional) { fprintf(file, "{Optional "); print_completion_string( clang_getCompletionChunkCompletionString(completion_string, I), file); fprintf(file, "}"); continue; } text = clang_getCompletionChunkText(completion_string, I); cstr = clang_getCString(text); fprintf(file, "{%s %s}", clang_getCompletionChunkKindSpelling(Kind), cstr ? cstr : ""); clang_disposeString(text); } }
QVector<CodeCompletionChunk> CodeCompletionChunkConverter::optionalChunks(CXCompletionString completionString, uint chunkIndex) { CodeCompletionChunkConverter converter; converter.extractOptionalCompletionChunks(clang_getCompletionChunkCompletionString(completionString, chunkIndex)); return converter.chunks; }
void CodeCompletionChunkConverter::extractOptionalCompletionChunks(CXCompletionString completionString) { const uint completionChunkCount = clang_getNumCompletionChunks(completionString); for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) { const CodeCompletionChunk::Kind kind = chunkKind(completionString, chunkIndex); if (kind == CodeCompletionChunk::Optional) extractOptionalCompletionChunks(clang_getCompletionChunkCompletionString(completionString, chunkIndex)); else chunks.append(CodeCompletionChunk(kind, chunkText(completionString, chunkIndex))); } }
std::string CompletionData::OptionalChunkToString( CXCompletionString completion_string, size_t chunk_num ) { std::string final_string; if ( !completion_string ) return final_string; CXCompletionString optional_completion_string = clang_getCompletionChunkCompletionString( completion_string, chunk_num ); if ( !optional_completion_string ) return final_string; size_t optional_num_chunks = clang_getNumCompletionChunks( optional_completion_string ); for ( size_t j = 0; j < optional_num_chunks; ++j ) { CXCompletionChunkKind kind = clang_getCompletionChunkKind( optional_completion_string, j ); if ( kind == CXCompletionChunk_Optional ) { final_string.append( OptionalChunkToString( optional_completion_string, j ) ); } else if ( kind == CXCompletionChunk_Placeholder ) { final_string.append( "[" + ChunkToString( optional_completion_string, j ) + "]" ); } else if ( kind == CXCompletionChunk_CurrentParameter ) { current_arg_ = "[" + ChunkToString( optional_completion_string, j ) + "]"; final_string.append( "☞ " + current_arg_ ); } else { final_string.append( ChunkToString( optional_completion_string, j ) ); } } return final_string; }
/* Print the completion line except the header term (COMPLETION: TypedText), * the output format should be identical with the result of clang -cc1 * -code-completion-at. Here are some sample outputs from the clang code * completion process: COMPLETION: short COMPLETION: signed COMPLETION: static COMPLETION: Pattern : static_cast<<#type#>>(<#expression#>) COMPLETION: struct * However, here we don't handle Pattern explicitly because the emacs * script would simply drop those pattern lines with an regexp T T */ static void completion_printAllCompletionTerms( CXCompletionString completion_string, FILE *fp) { int i_chunk = 0; int n_chunks = clang_getNumCompletionChunks(completion_string); CXString chk_text; enum CXCompletionChunkKind chk_kind; for ( ; i_chunk < n_chunks; i_chunk++) { /* get the type and completion text of this chunk */ chk_kind = clang_getCompletionChunkKind(completion_string, i_chunk); chk_text = clang_getCompletionChunkText(completion_string, i_chunk); /* differenct kinds of chunks has various output formats */ switch (chk_kind) { case CXCompletionChunk_Placeholder: fprintf(fp, "<#%s#>", clang_getCString(chk_text)); break; case CXCompletionChunk_ResultType: fprintf(fp, "[#%s#]", clang_getCString(chk_text)); break; case CXCompletionChunk_Optional: /* print optional term in a recursive way */ fprintf(fp, "{#"); completion_printAllCompletionTerms( clang_getCompletionChunkCompletionString(completion_string, i_chunk), fp); fprintf(fp, "#}"); break; default: fprintf(fp, "%s", clang_getCString(chk_text)); } clang_disposeString(chk_text); } }
code_completion_string code_completion_string::chunkCompletionString(unsigned idx) const { return { clang_getCompletionChunkCompletionString(str, idx) }; }
QList<ClangCodeCompletionItem> TranslationUnit::completeAt( const int line , const int column , const unsigned completion_flags , const clang::unsaved_files_list& unsaved_files , const PluginConfiguration::sanitize_rules_list_type& sanitize_rules ) { auto files = unsaved_files.get(); #ifndef NDEBUG for (auto& item : files) assert( "Sanity check" && item.Filename && std::strlen(item.Filename) && item.Contents && item.Length ); #endif clang::DCXCodeCompleteResults res = { clang_codeCompleteAt( m_unit , m_filename.constData() , unsigned(line) , unsigned(column) , files.data() , files.size() , completion_flags ) }; if (!res) { throw Exception::CompletionFailure( i18nc("@item:intext", "Unable to perform code completion").toAscii().constData() ); } #if 0 clang_sortCodeCompletionResults(res->Results, res->NumResults); #endif // Collect some diagnostic SPAM for (auto i = 0u; i < clang_codeCompleteGetNumDiagnostics(res); ++i) { clang::DCXDiagnostic diag = {clang_codeCompleteGetDiagnostic(res, i)}; appendDiagnostic(diag); } QList<ClangCodeCompletionItem> completions; completions.reserve(res->NumResults); // Peallocate enough space for completion results // Lets look what we've got... for (auto i = 0u; i < res->NumResults; ++i) { const auto str = res->Results[i].CompletionString; const auto priority = clang_getCompletionPriority(str); const auto cursor_kind = res->Results[i].CursorKind; debugShowCompletionResult(i, priority, str, cursor_kind); // Skip unusable completions // 0) check availability const auto availability = clang_getCompletionAvailability(str); if (availability != CXAvailability_Available && availability != CXAvailability_Deprecated) { kDebug(DEBUG_AREA) << "!! Skip result" << i << "as not available"; continue; } // 1) check usefulness /// \todo Make it configurable if (cursor_kind == CXCursor_NotImplemented) continue; // Collect all completion chunks and from a format string QString text_before; QString typed_text; QString text_after; QStringList placeholders; int optional_placeholers_start_position = -1; // A lambda to append given text to different parts // of future completion string, depending on already processed text auto appender = [&](const QString& text) { if (typed_text.isEmpty()) text_before += text; else text_after += text; }; auto skip_this_item = false; for ( auto j = 0u , chunks = clang_getNumCompletionChunks(str) ; j < chunks && !skip_this_item ; ++j ) { auto kind = clang_getCompletionChunkKind(str, j); auto text = toString(clang::DCXString{clang_getCompletionChunkText(str, j)}); switch (kind) { // Text that a user would be expected to type to get this code-completion result case CXCompletionChunk_TypedText: // Text that should be inserted as part of a code-completion result case CXCompletionChunk_Text: { auto p = sanitize(text, sanitize_rules);// Pipe given piece of text through sanitizer if (p.first) typed_text += p.second; else // Go for next completion item skip_this_item = true; break; } // Placeholder text that should be replaced by the user case CXCompletionChunk_Placeholder: { auto p = sanitize(text, sanitize_rules);// Pipe given piece of text through sanitizer if (p.first) { appender( QLatin1String{"%"} + QString::number(placeholders.size() + 1) + QLatin1String{"%"} ); placeholders.push_back(p.second); } else // Go for next completion item skip_this_item = true; break; } // A code-completion string that describes "optional" text that // could be a part of the template (but is not required) case CXCompletionChunk_Optional: { auto ostr = clang_getCompletionChunkCompletionString(str, j); for ( auto oci = 0u , ocn = clang_getNumCompletionChunks(ostr) ; oci < ocn ; ++oci ) { auto otext = toString(clang::DCXString{clang_getCompletionChunkText(ostr, oci)}); // Pipe given piece of text through sanitizer auto p = sanitize(otext, sanitize_rules); if (p.first) { auto okind = clang::kind_of(ostr, oci); if (okind == CXCompletionChunk_Placeholder) { appender( QLatin1String{"%"} + QString::number(placeholders.size() + 1) + QLatin1String{"%"} ); placeholders.push_back(p.second); optional_placeholers_start_position = placeholders.size(); } else appender(p.second); } else { skip_this_item = true; break; } } break; } case CXCompletionChunk_ResultType: case CXCompletionChunk_LeftParen: case CXCompletionChunk_RightParen: case CXCompletionChunk_LeftBracket: case CXCompletionChunk_RightBracket: case CXCompletionChunk_LeftBrace: case CXCompletionChunk_RightBrace: case CXCompletionChunk_LeftAngle: case CXCompletionChunk_RightAngle: case CXCompletionChunk_Comma: case CXCompletionChunk_Colon: case CXCompletionChunk_SemiColon: case CXCompletionChunk_Equal: case CXCompletionChunk_CurrentParameter: case CXCompletionChunk_HorizontalSpace: /// \todo Kate can't handle \c '\n' well in completions list case CXCompletionChunk_VerticalSpace: { auto p = sanitize(text, sanitize_rules);// Pipe given piece of text through sanitizer if (p.first) appender(p.second); else // Go for next completion item skip_this_item = true; break; } // Informative text that should be displayed but never inserted // as part of the template case CXCompletionChunk_Informative: // Informative text before CXCompletionChunk_TypedText usually // just a method scope (i.e. long name of an owner class) // and it's useless for completer cuz it can group items // by parent already... if (!typed_text.isEmpty()) { // Pipe given piece of text through sanitizer auto p = sanitize(text, sanitize_rules); if (p.first) appender(p.second); else // Go for next completion item skip_this_item = true; } break; default: break; } } // Does it pass the completion items sanitizer? if (skip_this_item) continue; // No! Skip it! assert("Priority expected to be less than 100" && priority < 101u); const auto comment = toString(clang::DCXString{clang_getCompletionBriefComment(str)}); // completions.push_back({ makeParentText(str, cursor_kind) , text_before , typed_text , text_after , placeholders , optional_placeholers_start_position , priority , cursor_kind , comment , availability == CXAvailability_Deprecated }); } return completions; }
void ClangDriver::DoParseCompletionString(CXCompletionString str, int depth, wxString& entryName, wxString& signature, wxString& completeString, wxString& returnValue) { bool collectingSignature = false; int numOfChunks = clang_getNumCompletionChunks(str); for(int j = 0; j < numOfChunks; j++) { CXString chunkText = clang_getCompletionChunkText(str, j); CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(str, j); switch(chunkKind) { case CXCompletionChunk_TypedText: entryName = wxString(clang_getCString(chunkText), wxConvUTF8); completeString += entryName; break; case CXCompletionChunk_ResultType: completeString += wxString(clang_getCString(chunkText), wxConvUTF8); completeString += wxT(" "); returnValue = wxString(clang_getCString(chunkText), wxConvUTF8); break; case CXCompletionChunk_Optional: { // Optional argument CXCompletionString optStr = clang_getCompletionChunkCompletionString(str, j); wxString optionalString; wxString dummy; // Once we hit the 'Optional Chunk' only the 'completeString' is matter DoParseCompletionString(optStr, depth + 1, dummy, dummy, optionalString, dummy); if(collectingSignature) { signature += optionalString; } completeString += optionalString; } break; case CXCompletionChunk_LeftParen: collectingSignature = true; signature += wxT("("); completeString += wxT("("); break; case CXCompletionChunk_RightParen: collectingSignature = true; signature += wxT(")"); completeString += wxT(")"); break; default: if(collectingSignature) { signature += wxString(clang_getCString(chunkText), wxConvUTF8); } completeString += wxString(clang_getCString(chunkText), wxConvUTF8); break; } clang_disposeString(chunkText); } // To make this tag compatible with ctags one, we need to place // a /^ and $/ in the pattern string (we add this only to the top level completionString) if(depth == 0) { completeString.Prepend(wxT("/^ ")); completeString.Append(wxT(" $/")); } }