std::vector<ClangPlugin::CCToken> ClangPlugin::GetTokenAt(int pos, cbEditor* ed, bool& /*allowCallTip*/) { #ifdef CLANGPLUGIN_TRACE_FUNCTIONS fprintf(stdout,"%s\n", __PRETTY_FUNCTION__); #endif std::vector<CCToken> tokens; if (ed != m_pLastEditor) { return tokens; } if (m_TranslUnitId == wxNOT_FOUND) { return tokens; } cbStyledTextCtrl* stc = ed->GetControl(); if (stc->GetTextRange(pos - 1, pos + 1).Strip().IsEmpty()) return tokens; const unsigned int line = stc->LineFromPosition(pos); ClTokenPosition loc(line + 1, pos - stc->PositionFromLine(line) + 1); ClangProxy::GetTokensAtJob job( cbEVT_CLANG_SYNCTASK_FINISHED, idClangSyncTask, ed->GetFilename(), loc, m_TranslUnitId); job.WaitCompletion(50); wxStringVec names = job.GetResults(); for (wxStringVec::const_iterator nmIt = names.begin(); nmIt != names.end(); ++nmIt) tokens.push_back(CCToken(-1, *nmIt)); return tokens; }
std::vector<ClangPlugin::CCToken> ClangPlugin::GetTokenAt(int pos, cbEditor* ed, bool& allowCallTip) { std::vector<CCToken> tokens; if (ed != m_pLastEditor) { m_TranslUnitId = m_Proxy.GetTranslationUnitId(ed->GetFilename()); m_pLastEditor = ed; } if (m_TranslUnitId == wxNOT_FOUND) return tokens; cbStyledTextCtrl* stc = ed->GetControl(); if (stc->GetTextRange(pos - 1, pos + 1).Strip().IsEmpty()) return tokens; const int line = stc->LineFromPosition(pos); const int column = pos - stc->PositionFromLine(line); wxStringVec names; m_Proxy.GetTokensAt(ed->GetFilename(), line + 1, column + 1, m_TranslUnitId, names); for (wxStringVec::const_iterator nmIt = names.begin(); nmIt != names.end(); ++nmIt) tokens.push_back(CCToken(-1, *nmIt)); return tokens; }
void cbCodeCompletionPlugin::DoAutocomplete(const wxString& token, cbEditor* ed) { DoAutocomplete(CCToken(-1, token), ed); }
std::vector<ClangPlugin::CCToken> ClangPlugin::GetAutocompList(bool isAuto, cbEditor* ed, int& tknStart, int& tknEnd) { std::vector<CCToken> tokens; if (ed != m_pLastEditor) { m_TranslUnitId = m_Proxy.GetTranslationUnitId(ed->GetFilename()); m_pLastEditor = ed; } if (m_TranslUnitId == wxNOT_FOUND) { Manager::Get()->GetLogManager()->LogWarning(wxT("ClangLib: m_TranslUnitId == wxNOT_FOUND, cannot complete in file ") + ed->GetFilename()); return tokens; } cbStyledTextCtrl* stc = ed->GetControl(); const int style = stc->GetStyleAt(tknEnd); const wxChar curChar = stc->GetCharAt(tknEnd - 1); if (isAuto) // filter illogical cases of auto-launch { if ( ( curChar == wxT(':') // scope operator && stc->GetCharAt(tknEnd - 2) != wxT(':') ) || ( curChar == wxT('>') // '->' && stc->GetCharAt(tknEnd - 2) != wxT('-') ) || ( wxString(wxT("<\"/")).Find(curChar) != wxNOT_FOUND // #include directive (TODO: enumerate completable include files) && !stc->IsPreprocessor(style) ) ) { return tokens; } } std::vector<ClToken> tknResults; const int line = stc->LineFromPosition(tknStart); std::map<wxString, wxString> unsavedFiles; EditorManager* edMgr = Manager::Get()->GetEditorManager(); for (int i = 0; i < edMgr->GetEditorsCount(); ++i) { cbEditor* editor = edMgr->GetBuiltinEditor(i); if (editor && editor->GetModified()) unsavedFiles.insert(std::make_pair(editor->GetFilename(), editor->GetControl()->GetText())); } const int lnStart = stc->PositionFromLine(line); int column = tknStart - lnStart; for (; column > 0; --column) { if ( !wxIsspace(stc->GetCharAt(lnStart + column - 1)) || (column != 1 && !wxIsspace(stc->GetCharAt(lnStart + column - 2))) ) { break; } } m_Proxy.CodeCompleteAt(isAuto, ed->GetFilename(), line + 1, column + 1, m_TranslUnitId, unsavedFiles, tknResults); const wxString& prefix = stc->GetTextRange(tknStart, tknEnd).Lower(); bool includeCtors = true; // sometimes we get a lot of these for (int i = tknStart - 1; i > 0; --i) { wxChar chr = stc->GetCharAt(i); if (!wxIsspace(chr)) { if (chr == wxT(';') || chr == wxT('}')) // last non-whitespace character includeCtors = false; // filter out ctors (they are unlikely to be wanted in this situation) break; } } if (prefix.Length() > 3) // larger context, match the prefix at any point in the token { for (std::vector<ClToken>::const_iterator tknIt = tknResults.begin(); tknIt != tknResults.end(); ++tknIt) { if (tknIt->name.Lower().Find(prefix) != wxNOT_FOUND && (includeCtors || tknIt->category != tcCtorPublic)) tokens.push_back(CCToken(tknIt->id, tknIt->name, tknIt->name, tknIt->weight, tknIt->category)); } } else if (prefix.IsEmpty()) { for (std::vector<ClToken>::const_iterator tknIt = tknResults.begin(); tknIt != tknResults.end(); ++tknIt) { if (!tknIt->name.StartsWith(wxT("operator")) && (includeCtors || tknIt->category != tcCtorPublic)) // it is rather unlikely for an operator to be the desired completion tokens.push_back(CCToken(tknIt->id, tknIt->name, tknIt->name, tknIt->weight, tknIt->category)); } } else // smaller context, only allow matches of the prefix at the beginning of the token { for (std::vector<ClToken>::const_iterator tknIt = tknResults.begin(); tknIt != tknResults.end(); ++tknIt) { if (tknIt->name.Lower().StartsWith(prefix) && (includeCtors || tknIt->category != tcCtorPublic)) tokens.push_back(CCToken(tknIt->id, tknIt->name, tknIt->name, tknIt->weight, tknIt->category)); } } if (!tokens.empty()) { if (prefix.IsEmpty() && tokens.size() > 1500) // reduce to give only top matches { std::partial_sort(tokens.begin(), tokens.begin() + 1000, tokens.end(), PrioritySorter()); tokens.erase(tokens.begin() + 1000, tokens.end()); } const int imgCount = m_ImageList.GetImageCount(); for (int i = 0; i < imgCount; ++i) stc->RegisterImage(i, m_ImageList.GetBitmap(i)); bool isPP = stc->GetLine(line).Strip(wxString::leading).StartsWith(wxT("#")); std::set<int> usedWeights; for (std::vector<CCToken>::iterator tknIt = tokens.begin(); tknIt != tokens.end(); ++tknIt) { usedWeights.insert(tknIt->weight); switch (tknIt->category) { case tcNone: if (isPP) tknIt->category = tcMacroDef; else if (std::binary_search(m_CppKeywords.begin(), m_CppKeywords.end(), GetActualName(tknIt->name))) tknIt->category = tcLangKeyword; break; case tcClass: case tcCtorPublic: case tcDtorPublic: case tcFuncPublic: case tcVarPublic: case tcEnum: case tcTypedef: m_Proxy.RefineTokenType(m_TranslUnitId, tknIt->id, tknIt->category); break; default: break; } } // Clang sometimes gives many weight values, which can make completion more difficult // because results are less alphabetical. Use a compression map on the lower priority // values (higher numbers) to reduce the total number of weights used. if (usedWeights.size() > 3) { std::vector<int> weightsVec(usedWeights.begin(), usedWeights.end()); std::map<int, int> weightCompr; weightCompr[weightsVec[0]] = weightsVec[0]; weightCompr[weightsVec[1]] = weightsVec[1]; int factor = (weightsVec.size() > 7 ? 3 : 2); for (size_t i = 2; i < weightsVec.size(); ++i) weightCompr[weightsVec[i]] = weightsVec[(i - 2) / factor + 2]; for (std::vector<CCToken>::iterator tknIt = tokens.begin(); tknIt != tokens.end(); ++tknIt) { tknIt->weight = weightCompr[tknIt->weight]; } } } return tokens; }