void PHPCodeCompletion::DoShowCompletionBox(const PHPEntityBase::List_t& entries, PHPExpression::Ptr_t expr) { wxCodeCompletionBoxEntry::Vec_t ccEntries; TagEntryPtrVector_t tags; wxStringSet_t uniqueEntries; // search for the old item PHPEntityBase::List_t::const_iterator iter = entries.begin(); for(; iter != entries.end(); ++iter) { PHPEntityBase::Ptr_t entry = *iter; if(uniqueEntries.count(entry->GetFullName()) == 0) { uniqueEntries.insert(entry->GetFullName()); } else { // don't add duplicate entries continue; } PHPEntityBase::Ptr_t ns = expr->GetSourceFile()->Namespace(); // the namespace at the source file TagEntryPtr t = DoPHPEntityToTagEntry(entry); tags.push_back(t); } std::sort(tags.begin(), tags.end(), _SAscendingSort()); for(size_t i = 0; i < tags.size(); ++i) { wxCodeCompletionBoxEntry::Ptr_t ccEntry = wxCodeCompletionBox::TagToEntry(tags.at(i)); ccEntry->SetComment(tags.at(i)->GetComment()); ccEntries.push_back(ccEntry); } wxCodeCompletionBoxManager::Get().ShowCompletionBox( m_manager->GetActiveEditor()->GetCtrl(), ccEntries, wxCodeCompletionBox::kRefreshOnKeyType, wxNOT_FOUND); }
void PHPCodeCompletion::DoShowCompletionBox(const PHPEntityBase::List_t& entries, PHPExpression::Ptr_t expr) { std::vector<TagEntryPtr> tags; wxStringSet_t uniqueEntries; // search for the old item PHPEntityBase::List_t::const_iterator iter = entries.begin(); for(; iter != entries.end(); ++iter) { PHPEntityBase::Ptr_t entry = *iter; if(uniqueEntries.count(entry->GetFullName()) == 0) { uniqueEntries.insert(entry->GetFullName()); } else { // don't add duplicate entries continue; } PHPEntityBase::Ptr_t ns = expr->GetSourceFile()->Namespace(); // the namespace at the source file TagEntryPtr t = DoPHPEntityToTagEntry(entry); t->SetUserData(new PHPCCUserData(entry)); tags.push_back(t); } if(tags.empty()) return; std::sort(tags.begin(), tags.end(), _SAscendingSort()); m_manager->GetActiveEditor()->ShowCompletionBox(tags, expr->GetFilter(), false, this); }
bool PHPRefactoring::FindByName(const PHPEntityBase::List_t& entries, const wxString& name) const { PHPEntityBase::List_t::const_iterator iter = entries.begin(); for(; iter != entries.end(); ++iter) { if((*iter)->GetFullName() == name) { return true; } } return false; }
void PHPCodeCompletion::OnFindSymbol(clCodeCompletionEvent& e) { e.Skip(); if(PHPWorkspace::Get()->IsOpen()) { if(!CanCodeComplete(e)) return; e.Skip(false); IEditor* editor = dynamic_cast<IEditor*>(e.GetEditor()); if(editor) { wxString word = editor->GetWordAtCaret(); if(word.IsEmpty()) return; PHPEntityBase::List_t symbols = m_lookupTable.FindSymbol(word); if(symbols.size() == 1) { PHPEntityBase::Ptr_t match = *symbols.begin(); DoOpenEditorForEntry(match); } else { // Convert the matches to clSelectSymbolDialogEntry::List_t clSelectSymbolDialogEntry::List_t entries; std::for_each(symbols.begin(), symbols.end(), [&](PHPEntityBase::Ptr_t entry) { TagEntryPtr tag = DoPHPEntityToTagEntry(entry); wxBitmap bmp = wxCodeCompletionBox::GetBitmap(tag); clSelectSymbolDialogEntry m; m.bmp = bmp; m.name = entry->GetFullName(); m.clientData = new PHPFindSymbol_ClientData(entry); m.help = tag->GetKind(); entries.push_back(m); }); // Show selection dialog clSelectSymbolDialog dlg(EventNotifier::Get()->TopFrame(), entries); if(dlg.ShowModal() != wxID_OK) return; PHPFindSymbol_ClientData* cd = dynamic_cast<PHPFindSymbol_ClientData*>(dlg.GetSelection()); if(cd) { DoOpenEditorForEntry(cd->m_ptr); } } } } }
void PHPCodeCompletion::OnCodeComplete(clCodeCompletionEvent& e) { e.Skip(true); if(PHPWorkspace::Get()->IsOpen()) { IEditor* editor = dynamic_cast<IEditor*>(e.GetEditor()); if(editor && IsPHPFile(editor)) { e.Skip(false); // Update the settings TagsOptionsData d; clConfig ccConfig("code-completion.conf"); ccConfig.ReadItem(&d); m_lookupTable.SetSizeLimit(d.GetCcNumberOfDisplayItems()); // Check if the code completion was triggered due to user // typing '(', in this case, call OnFunctionCallTip() wxChar charAtPos = editor->GetCharAtPos(editor->GetCurrentPosition() - 1); if(charAtPos == '(') { OnFunctionCallTip(e); } else { // Perform the code completion here PHPExpression::Ptr_t expr(new PHPExpression(editor->GetTextRange(0, e.GetPosition()))); bool isExprStartsWithOpenTag = expr->IsExprStartsWithOpenTag(); PHPEntityBase::Ptr_t entity = expr->Resolve(m_lookupTable, editor->GetFileName().GetFullPath()); if(entity) { // Suggets members for the resolved entity PHPEntityBase::List_t matches; expr->Suggest(entity, m_lookupTable, matches); if(!expr->GetFilter().IsEmpty() && (expr->GetCount() == 0)) { // Word completion PHPEntityBase::List_t keywords = PhpKeywords(expr->GetFilter()); // Preprend the keywords matches.insert(matches.end(), keywords.begin(), keywords.end()); // Did user typed "<?ph" or "<?php" ?? // If so, clear the matches if(isExprStartsWithOpenTag && (expr->GetFilter() == "ph" || expr->GetFilter() == "php")) { matches.clear(); } } // Remove duplicates from the list if(!matches.empty()) { // Show the code completion box DoShowCompletionBox(matches, expr); } } } } } }
void PHPExpression::DoMakeUnique(PHPEntityBase::List_t& matches) { std::set<wxString> uniqueNames; PHPEntityBase::List_t uniqueList; for(PHPEntityBase::List_t::iterator iter = matches.begin(); iter != matches.end(); ++iter) { if(uniqueNames.count((*iter)->GetFullName()) == 0) { uniqueNames.insert((*iter)->GetFullName()); uniqueList.push_back(*iter); } } matches.swap(uniqueList); }
void OpenResourceDlg::DoGetResources(const wxString& filter) { m_resources.clear(); PHPEntityBase::List_t matches; m_table.LoadAllByFilter(matches, filter); // Convert the PHP matches into resources PHPEntityBase::List_t::iterator iter = matches.begin(); m_resources.reserve(matches.size()); for(; iter != matches.end(); ++iter) { PHPEntityBase::Ptr_t match = *iter; if(FileUtils::FuzzyMatch(filter, match->GetFullName())) { ResourceItem resource; resource.displayName = match->GetDisplayName(); resource.filename = match->GetFilename(); resource.line = match->GetLine(); resource.SetType(match); m_resources.push_back(resource); } } }
PHPEntityBase::Ptr_t PHPCodeCompletion::DoGetPHPEntryUnderTheAtPos(IEditor* editor, int pos, bool forFunctionCalltip) { if(!PHPWorkspace::Get()->IsOpen()) return PHPEntityBase::Ptr_t(NULL); pos = editor->GetCtrl()->WordEndPosition(pos, true); // Get the expression under the caret wxString unsavedBuffer = editor->GetTextRange(0, pos); wxString filter; PHPEntityBase::Ptr_t resolved; // Parse the source file PHPSourceFile source(unsavedBuffer); source.SetFilename(editor->GetFileName()); source.SetParseFunctionBody(false); source.Parse(); PHPEntityBase::Ptr_t currentScope = source.CurrentScope(); if(currentScope && currentScope->Is(kEntityTypeClass)) { // we are trying to resolve a 'word' under the caret within the class // body but _not_ within a function body (i.e. it can only be // a definition of some kind) // try to construct an expression that will work int wordStart = editor->GetCtrl()->WordStartPosition(pos, true); wxString theWord = editor->GetTextRange(wordStart, pos); wxString theWordNoDollar = theWord; if(theWord.StartsWith("$")) { theWordNoDollar = theWord.Mid(1); } PHPExpression expr2(unsavedBuffer, "<?php $this->" + theWordNoDollar, forFunctionCalltip); resolved = expr2.Resolve(m_lookupTable, editor->GetFileName().GetFullPath()); filter = expr2.GetFilter(); if(!resolved) { // Maybe its a static member/function/const, try using static keyword PHPExpression expr3(unsavedBuffer, "<?php static::" + theWord, forFunctionCalltip); resolved = expr2.Resolve(m_lookupTable, editor->GetFileName().GetFullPath()); filter = expr2.GetFilter(); } } if(!resolved) { PHPExpression expr(unsavedBuffer, "", forFunctionCalltip); resolved = expr.Resolve(m_lookupTable, editor->GetFileName().GetFullPath()); filter = expr.GetFilter(); } if(resolved && !filter.IsEmpty()) { resolved = m_lookupTable.FindMemberOf(resolved->GetDbId(), filter); if(!resolved) { // Fallback to functions and constants PHPEntityBase::List_t children = m_lookupTable.FindGlobalFunctionAndConsts(PHPLookupTable::kLookupFlags_ExactMatch, filter); if(children.size() == 1) { resolved = *children.begin(); } } if(resolved && resolved->Is(kEntityTypeFunction)) { // for a function, we need to load its children (function arguments) resolved->SetChildren(m_lookupTable.LoadFunctionArguments(resolved->GetDbId())); } else if(resolved && resolved->Is(kEntityTypeFunctionAlias)) { // for a function alias, we need to load the actual functions' children (function arguments) PHPEntityBase::Ptr_t realFunc = resolved->Cast<PHPEntityFunctionAlias>()->GetFunc(); realFunc->SetChildren(m_lookupTable.LoadFunctionArguments(realFunc->GetDbId())); } } return resolved; }
void PHPExpression::Suggest(PHPEntityBase::Ptr_t resolved, PHPLookupTable& lookup, PHPEntityBase::List_t& matches) { // sanity if(!resolved) return; PHPEntityBase::Ptr_t currentScope = GetSourceFile()->CurrentScope(); // GetCount() == 0 && !GetFilter().IsEmpty() i.e. a word completion is required. // We enhance the list with the following: // - PHP keywords // - Global functions // - Global constants // - Function arguments // - Local variables (of the current scope) // - And aliases e.g. 'use foo\bar as Bar;' if(GetCount() == 0 && !GetFilter().IsEmpty()) { // For functions and constants, PHP will fall back to global functions or constants if a // namespaced function or constant does not exist. PHPEntityBase::List_t globals = lookup.FindGlobalFunctionAndConsts(PHPLookupTable::kLookupFlags_Contains, GetFilter()); matches.insert(matches.end(), globals.begin(), globals.end()); if(currentScope && (currentScope->Is(kEntityTypeFunction) || currentScope->Is(kEntityTypeNamespace))) { // If the current scope is a function // add the local variables + function arguments to the current list of matches const PHPEntityBase::List_t& children = currentScope->GetChildren(); PHPEntityBase::List_t::const_iterator iter = children.begin(); for(; iter != children.end(); ++iter) { PHPEntityBase::Ptr_t child = *iter; if(child->Is(kEntityTypeVariable) && child->GetShortName().Contains(GetFilter()) && child->GetShortName() != GetFilter()) { matches.push_back(child); } } } { // Add aliases PHPEntityBase::List_t aliases = GetSourceFile()->GetAliases(); PHPEntityBase::List_t::iterator iter = aliases.begin(); for(; iter != aliases.end(); ++iter) { if((*iter)->GetShortName().Contains(GetFilter())) { matches.push_back(*iter); } } } { // Add $this incase we are inside a class (but only if '$this' contains the filter string) wxString lcFilter = GetFilter().Lower(); if(GetSourceFile()->Class() && wxString("$this").Contains(lcFilter)) { PHPEntityBase::Ptr_t thiz(new PHPEntityVariable()); thiz->SetFullName("$this"); thiz->SetShortName("$this"); thiz->SetFilename(currentScope->GetFilename()); matches.push_back(thiz); } } } // Add the scoped matches // for the code completion size_t flags = PHPLookupTable::kLookupFlags_Contains | GetLookupFlags(); if(resolved->Is(kEntityTypeClass)) { if(resolved->Cast<PHPEntityClass>()->IsInterface() || resolved->Cast<PHPEntityClass>()->IsAbstractClass()) { flags |= PHPLookupTable::kLookupFlags_IncludeAbstractMethods; } } PHPEntityBase::List_t scopeChildren = lookup.FindChildren(resolved->GetDbId(), flags, GetFilter()); matches.insert(matches.end(), scopeChildren.begin(), scopeChildren.end()); // Incase the resolved is a namespace, suggest all children namespaces if(resolved->Is(kEntityTypeNamespace)) { PHPEntityBase::List_t namespaces = lookup.FindNamespaces(resolved->GetFullName(), GetFilter()); matches.insert(matches.end(), namespaces.begin(), namespaces.end()); } // and make the list unique DoMakeUnique(matches); }