void ClangCodeCompletion::HighlightOccurrences(cbEditor* ed) { ClTranslUnitId translId = GetCurrentTranslationUnitId(); cbStyledTextCtrl* stc = ed->GetControl(); int pos = stc->GetCurrentPos(); const wxChar ch = stc->GetCharAt(pos); if (pos > 0 && (wxIsspace(ch) || (ch != wxT('_') && wxIspunct(ch))) && !wxIsspace(stc->GetCharAt(pos - 1))) { --pos; } // chosen a high value for indicator, hoping not to interfere with the indicators used by some lexers // if they get updated from deprecated old style indicators someday. const int theIndicator = 16; stc->SetIndicatorCurrent(theIndicator); // Set Styling: // clear all style indications set in a previous run (is also done once after text gets unselected) stc->IndicatorClearRange(0, stc->GetLength()); if (stc->GetTextRange(pos - 1, pos + 1).Strip().IsEmpty()) return; // TODO: use independent key wxColour highlightColour(Manager::Get()->GetColourManager()->GetColour(wxT("editor_highlight_occurrence"))); stc->IndicatorSetStyle(theIndicator, wxSCI_INDIC_HIGHLIGHT); stc->IndicatorSetForeground(theIndicator, highlightColour); stc->IndicatorSetUnder(theIndicator, true); const int line = stc->LineFromPosition(pos); ClTokenPosition loc(line + 1, pos - stc->PositionFromLine(line) + 1); std::vector< std::pair<int, int> > occurrences; m_pClangPlugin->GetOccurrencesOf( translId, ed->GetFilename(), loc, 100, occurrences ); for (std::vector< std::pair<int, int> >::const_iterator tkn = occurrences.begin(); tkn != occurrences.end(); ++tkn) { stc->IndicatorFillRange(tkn->first, tkn->second); } }
void ClangCodeCompletion::OnTimer(wxTimerEvent& event) { if (!IsAttached()) { return; } const int evId = event.GetId(); cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor(); if (!ed) { return; } if (evId == idReparseTimer) // m_ReparseTimer { //wxCommandEvent evt(cbEVT_COMMAND_REPARSE, idReparse); //AddPendingEvent(evt); m_pClangPlugin->RequestReparse( GetCurrentTranslationUnitId(), ed->GetFilename() ); } else if (evId == idHighlightTimer) { //if (m_TranslUnitId == wxNOT_FOUND) //{ // return; //} HighlightOccurrences(ed); } else if (evId == idDiagnosticTimer) { //wxCommandEvent evt(cbEVT_COMMAND_DIAGNOSEED, idDiagnoseEd); //AddPendingEvent(evt); } else { event.Skip(); } }
void ClangDiagnostics::OnDiagnostics( ClangEvent& event ) { ClDiagnosticLevel diagLv = dlFull; // TODO bool update = false; EditorManager* edMgr = Manager::Get()->GetEditorManager(); cbEditor* ed = edMgr->GetBuiltinActiveEditor(); if (!ed) { std::cout<<"No editor..."<<std::endl; return; } if( event.GetTranslationUnitId() != GetCurrentTranslationUnitId() ) { // Switched translation unit before event delivered return; } if( (diagLv == dlFull)&&(event.GetLocation().line != 0)&&(event.GetLocation().column != 0) ) { update = true; } const std::vector<ClDiagnostic>& diagnostics = event.GetDiagnosticResults(); cbStyledTextCtrl* stc = ed->GetControl(); int firstVisibleLine = stc->GetFirstVisibleLine(); if ((diagLv == dlFull)&&(!update) ) stc->AnnotationClearAll(); const int warningIndicator = 0; // predefined const int errorIndicator = 15; // hopefully we do not clash with someone else... stc->SetIndicatorCurrent(warningIndicator); if ( !update ) stc->IndicatorClearRange(0, stc->GetLength()); stc->IndicatorSetStyle(errorIndicator, wxSCI_INDIC_SQUIGGLE); stc->IndicatorSetForeground(errorIndicator, *wxRED); stc->SetIndicatorCurrent(errorIndicator); if ( !update ) stc->IndicatorClearRange(0, stc->GetLength()); const wxString& filename = ed->GetFilename(); if ( (diagLv == dlFull)&&(update) ) { int line = event.GetLocation().line-1; stc->AnnotationClearLine(line); } for ( std::vector<ClDiagnostic>::const_iterator dgItr = diagnostics.begin(); dgItr != diagnostics.end(); ++dgItr ) { //Manager::Get()->GetLogManager()->Log(dgItr->file + wxT(" ") + dgItr->message + F(wxT(" %d, %d"), dgItr->range.first, dgItr->range.second)); if (dgItr->file != filename) continue; if (diagLv == dlFull) { if( (!update) || ((int)dgItr->line == (int)event.GetLocation().line) ) { wxString str = stc->AnnotationGetText(dgItr->line - 1); if (!str.IsEmpty()) str += wxT('\n'); stc->AnnotationSetText(dgItr->line - 1, str + dgItr->message); stc->AnnotationSetStyle(dgItr->line - 1, 50); } } int pos = stc->PositionFromLine(dgItr->line - 1) + dgItr->range.first - 1; int range = dgItr->range.second - dgItr->range.first; if (range == 0) { range = stc->WordEndPosition(pos, true) - pos; if (range == 0) { pos = stc->WordStartPosition(pos, true); range = stc->WordEndPosition(pos, true) - pos; } } if (dgItr->severity == sError) stc->SetIndicatorCurrent(errorIndicator); else if ( dgItr != diagnostics.begin() && dgItr->line == (dgItr - 1)->line && dgItr->range.first <= (dgItr - 1)->range.second ) { continue; // do not overwrite the last indicator } else stc->SetIndicatorCurrent(warningIndicator); stc->IndicatorFillRange(pos, range); } if ( diagLv == dlFull ) { stc->AnnotationSetVisible(wxSCI_ANNOTATION_BOXED); stc->ScrollToLine(firstVisibleLine); } }
std::vector<cbCodeCompletionPlugin::CCToken> ClangCodeCompletion::GetAutocompList(bool isAuto, cbEditor* ed, int& tknStart, int& tknEnd) { #ifdef CLANGPLUGIN_TRACE_FUNCTIONS fprintf(stdout,"%s isAuto=%d\n", __PRETTY_FUNCTION__,(int)isAuto); #endif std::vector<cbCodeCompletionPlugin::CCToken> tokens; int CCOutstanding = m_CCOutstanding; if ((CCOutstanding > 0)&&(m_CCOutstandingPos != ed->GetControl()->GetCurrentPos())) { CCOutstanding = 0; } m_CCOutstanding = 0; ClTranslUnitId translUnitId = m_TranslUnitId; if( translUnitId != GetCurrentTranslationUnitId() ) return tokens; if (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; } } 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; } } 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; } } std::vector<ClToken> tknResults; if ((CCOutstanding == 0)||(m_CCOutstandingResults.size()==0)) { ClTokenPosition loc(line+1, column+1); //ClangProxy::CodeCompleteAtJob job( cbEVT_CLANG_SYNCTASK_FINISHED, idClangCodeCompleteTask, isAuto, ed->GetFilename(), loc, m_TranslUnitId, unsavedFiles); //m_Proxy.AppendPendingJob(job); unsigned long timeout = 40; if( !isAuto ) { timeout = 500; } if( wxCOND_TIMEOUT == m_pClangPlugin->GetCodeCompletionAt(translUnitId, ed->GetFilename(), loc, timeout, tknResults)) { if (wxGetLocalTime() - m_CCOutstandingLastMessageTime > 10) { //InfoWindow::Display(_("Code completion"), _("Busy parsing the document"), 1000); m_CCOutstandingLastMessageTime = wxGetLocalTime(); } //std::cout<<"Timeout waiting for code completion"<<std::endl; m_CCOutstanding++; m_CCOutstandingPos = ed->GetControl()->GetCurrentPos(); m_CCOutstandingResults.clear(); return tokens; } } else { tknResults = m_CCOutstandingResults; } //m_Proxy.CodeCompleteAt(isAuto, ed->GetFilename(), line + 1, column + 1, // m_TranslUnitId, unsavedFiles, tknResults); 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(cbCodeCompletionPlugin::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) { // it is rather unlikely for an operator to be the desired completion if (!tknIt->name.StartsWith(wxT("operator")) && (includeCtors || tknIt->category != tcCtorPublic)) tokens.push_back(cbCodeCompletionPlugin::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(cbCodeCompletionPlugin::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_pClangPlugin->GetImageList(translUnitId).GetImageCount(); for (int i = 0; i < imgCount; ++i) stc->RegisterImage(i, m_pClangPlugin->GetImageList(translUnitId).GetBitmap(i)); bool isPP = stc->GetLine(line).Strip(wxString::leading).StartsWith(wxT("#")); std::set<int> usedWeights; for (std::vector<cbCodeCompletionPlugin::CCToken>::iterator tknIt = tokens.begin(); tknIt != tokens.end(); ++tknIt) { wxStringVec keywords = m_pClangPlugin->GetKeywords(translUnitId); usedWeights.insert(tknIt->weight); switch (tknIt->category) { case tcNone: if (isPP) tknIt->category = tcMacroDef; else if (std::binary_search(keywords.begin(), keywords.end(), GetActualName(tknIt->name))) tknIt->category = tcLangKeyword; break; case tcClass: case tcCtorPublic: case tcDtorPublic: case tcFuncPublic: case tcVarPublic: case tcEnum: case tcTypedef: // TODO //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<cbCodeCompletionPlugin::CCToken>::iterator tknIt = tokens.begin(); tknIt != tokens.end(); ++tknIt) { tknIt->weight = weightCompr[tknIt->weight]; } } } std::cout<<"CodeCompletion finished"<<std::endl; return tokens; }
void ClangDiagnostics::OnDiagnosticsUpdated(ClangEvent& event) { event.Skip(); if (!IsAttached()) return; ClDiagnosticLevel diagLv = dlFull; // TODO bool update = false; EditorManager* edMgr = Manager::Get()->GetEditorManager(); cbEditor* ed = edMgr->GetBuiltinActiveEditor(); if (!ed) return; if (event.GetTranslationUnitId() != GetCurrentTranslationUnitId()) { CCLogger::Get()->DebugLog( wxT("OnDiagnostics: tu ID mismatch") ); // Switched translation unit before event delivered return; } const std::vector<ClDiagnostic>& diagnostics = event.GetDiagnosticResults(); if ( (diagLv == dlFull)&&(event.GetLocation().line != 0) && (event.GetLocation().column != 0) ) { CCLogger::Get()->DebugLog( wxT("OnDiagnostics: Doing partial update") ); update = true; } else { CCLogger::Get()->DebugLog( wxT("OnDiagnostics: Doing full update") ); m_Diagnostics = diagnostics; } cbStyledTextCtrl* stc = ed->GetControl(); int firstVisibleLine = stc->GetFirstVisibleLine(); const int warningIndicator = 0; // predefined const int errorIndicator = 15; // hopefully we do not clash with someone else... stc->SetIndicatorCurrent(warningIndicator); if (!update) stc->IndicatorClearRange(0, stc->GetLength()); stc->IndicatorSetStyle(errorIndicator, wxSCI_INDIC_SQUIGGLE); stc->IndicatorSetForeground(errorIndicator, *wxRED); stc->SetIndicatorCurrent(errorIndicator); if (!update) stc->IndicatorClearRange(0, stc->GetLength()); const wxString& filename = ed->GetFilename(); if (!m_bShowInline) stc->AnnotationClearAll(); else if ((diagLv == dlFull) && update) { int line = event.GetLocation().line-1; stc->AnnotationClearLine(line); } else stc->AnnotationClearAll(); int lastLine = 0; for (std::vector<ClDiagnostic>::const_iterator dgItr = diagnostics.begin(); dgItr != diagnostics.end(); ++dgItr) { Manager::Get()->GetLogManager()->Log(dgItr->file + wxT(" ") + dgItr->message + F(wxT(" %d, %d"), dgItr->range.first, dgItr->range.second)); if (dgItr->file != filename) { CCLogger::Get()->Log(wxT("WARNING: Filename mismatch in diagnostics !!")); continue; } if (update) { m_Diagnostics.push_back( *dgItr ); } if (diagLv == dlFull) { if (update && (lastLine != (dgItr->line - 1))) { stc->AnnotationClearLine(dgItr->line - 1); } if (m_bShowInline) { wxString str = stc->AnnotationGetText(dgItr->line - 1); if (!str.IsEmpty()) str += wxT('\n'); if (!str.Contains(dgItr->message)) { switch (dgItr->severity) { case sWarning: if (m_bShowWarning) { stc->AnnotationSetText(dgItr->line - 1, str + dgItr->message); stc->AnnotationSetStyle(dgItr->line - 1, 51); } break; case sError: if (m_bShowError) { stc->AnnotationSetText(dgItr->line - 1, str + dgItr->message); stc->AnnotationSetStyle(dgItr->line - 1, 52); } break; case sNote: break; } } } } int pos = stc->PositionFromLine(dgItr->line - 1) + dgItr->range.first - 1; int range = dgItr->range.second - dgItr->range.first; if (range == 0) { range = stc->WordEndPosition(pos, true) - pos; if (range == 0) { pos = stc->WordStartPosition(pos, true); range = stc->WordEndPosition(pos, true) - pos; } } if (dgItr->severity == sError) stc->SetIndicatorCurrent(errorIndicator); else if ( dgItr != diagnostics.begin() && dgItr->line == (dgItr - 1)->line && dgItr->range.first <= (dgItr - 1)->range.second ) { continue; // do not overwrite the last indicator } else stc->SetIndicatorCurrent(warningIndicator); stc->IndicatorFillRange(pos, range); lastLine = dgItr->line - 1; } if (diagLv == dlFull) { stc->AnnotationSetVisible(wxSCI_ANNOTATION_BOXED); stc->ScrollLines(firstVisibleLine - stc->GetFirstVisibleLine()); } }