void XMLCodeCompletion::OnCodeCompleted(clCodeCompletionEvent& event) { event.Skip(); if(event.GetEventObject() != this) { return; } // sanity IEditor* editor = clGetManager()->GetActiveEditor(); if(!editor) return; // HTML triggered the code complete? if(m_completeReason == kHtmlOpenSequence) { event.Skip(false); const wxString& selection = event.GetWord(); if(XMLBuffer::IsEmptyHtmlTag(selection) && !HasSpecialInsertPattern(selection)) { // an empty html tag, just complete it wxString textToInsert = selection; textToInsert << ">"; int selStart = GetWordStartPos(editor); int selEnd = editor->GetCurrentPosition(); if((selEnd - selStart) >= 0) { editor->SelectText(selStart, selEnd - selStart); editor->ReplaceSelection(textToInsert); editor->SetCaretAt(selStart + textToInsert.length()); } } else { wxString completePattern = GetCompletePattern(selection); int caretPos = completePattern.Find("|"); completePattern.Replace("|", ""); int selStart = GetWordStartPos(editor); int selEnd = editor->GetCurrentPosition(); if((selEnd - selStart) >= 0) { editor->SelectText(selStart, selEnd - selStart); editor->ReplaceSelection(completePattern); editor->SetCaretAt(selStart + caretPos); } } } else if(m_completeReason == kCloseSequence) { // User typed "</" event.Skip(false); const wxString& selection = event.GetWord(); int selStart = GetWordStartPos(editor); int selEnd = editor->GetCurrentPosition(); if((selEnd - selStart) >= 0) { editor->SelectText(selStart, selEnd - selStart); editor->ReplaceSelection(selection); editor->SetCaretAt(selStart + selection.length()); } } else { event.Skip(); } }
void XMLCodeCompletion::HtmlCodeComplete(IEditor* editor) { if(!m_htmlCcEnabeld) return; // Perform HTML code completion wxStyledTextCtrl* ctrl = editor->GetCtrl(); wxChar ch = ctrl->GetCharAt(ctrl->PositionBefore(ctrl->GetCurrentPos())); if(ch == '/') { SuggestClosingTag(editor, true); } else { wxCodeCompletionBox::BmpVec_t bitmaps; bitmaps.push_back(wxXmlResource::Get()->LoadBitmap("code-tags")); wxCodeCompletionBoxEntry::Vec_t entries; for(size_t i = 0; i < m_htmlCompletions.size(); ++i) { wxCodeCompletionBoxEntry::Ptr_t entry = wxCodeCompletionBoxEntry::New(m_htmlCompletions.at(i).m_tag, 0); entry->SetComment(m_htmlCompletions.at(i).m_comment); entries.push_back(entry); } m_completeReason = kHtmlOpenSequence; wxCodeCompletionBoxManager::Get().ShowCompletionBox(editor->GetCtrl(), entries, bitmaps, 0, GetWordStartPos(editor), this); } }
void XMLCodeCompletion::SuggestClosingTag(IEditor* editor, bool html) { // CC was triggered by "</" // Read backward until we find the matching open tag wxStyledTextCtrl* ctrl = editor->GetCtrl(); XMLBuffer buffer(ctrl->GetTextRange(0, ctrl->GetCurrentPos()), html); buffer.Parse(); if(buffer.InCData() || buffer.InComment()) { // dont offer code completion when inside CDATA or COMMENT blocks return; } XMLBuffer::Scope currentScope = buffer.GetCurrentScope(); if(!currentScope.IsOk()) return; wxCodeCompletionBox::BmpVec_t bitmaps; bitmaps.push_back(wxXmlResource::Get()->LoadBitmap("code-tags")); wxCodeCompletionBoxEntry::Vec_t entries; wxCodeCompletionBoxEntry::Ptr_t entry = wxCodeCompletionBoxEntry::New("</" + currentScope.tag + ">", 0); entries.push_back(entry); m_completeReason = kCloseSequence; wxCodeCompletionBoxManager::Get().ShowCompletionBox( editor->GetCtrl(), entries, bitmaps, 0, GetWordStartPos(editor), this); }
void wxCodeCompletionBoxManager::InsertSelection(wxCodeCompletionBoxEntry::Ptr_t match) { IManager* manager = ::clGetManager(); IEditor* editor = manager->GetActiveEditor(); wxString entryText = match->GetInsertText(); if(editor) { wxStyledTextCtrl* ctrl = editor->GetCtrl(); bool addParens(false); bool moveCaretRight = false; bool moveCaretLeft = false; int start = wxNOT_FOUND, end = wxNOT_FOUND; std::vector<std::pair<int, int> > ranges; if(ctrl->GetSelections() > 1) { for(int i = 0; i < ctrl->GetSelections(); ++i) { int nStart = GetWordStartPos(ctrl, ctrl->GetSelectionNCaret(i), entryText.Contains(":")); int nEnd = ctrl->GetSelectionNCaret(i); ranges.push_back(std::make_pair(nStart, nEnd)); } std::sort(ranges.begin(), ranges.end(), [&](const std::pair<int, int>& e1, const std::pair<int, int>& e2) { return e1.first < e2.first; }); } else { // Default behviour: remove the partial text from the editor and replace it // with the selection start = GetWordStartPos(ctrl, ctrl->GetCurrentPos(), entryText.Contains(":")); end = ctrl->GetCurrentPos(); ctrl->SetSelection(start, end); wxChar endChar = ctrl->GetCharAt(end); if((ctrl->GetCharAt(end) != '(')) { addParens = true; moveCaretLeft = true; } else if(endChar == '(') { moveCaretRight = true; } } if(match->IsFunction()) { // a function like wxString textToInsert = entryText.BeforeFirst('('); // Build the function signature wxString funcSig = match->GetSignature(); bool userProvidedSignature = (match->GetText().Find("(") != wxNOT_FOUND); clDEBUG() << "Inserting selection:" << textToInsert; clDEBUG() << "Signature is:" << funcSig; // Check if already have an open paren, don't add another if(addParens) { textToInsert << "()"; } if(!ranges.empty()) { // Multiple carets int offset = 0; for(size_t i = 0; i < ranges.size(); ++i) { int from = ranges.at(i).first; int to = ranges.at(i).second; from += offset; to += offset; // Once we enter that text into the editor, it will change the original // offsets (in most cases the entered text is larger than that typed text) offset += textToInsert.length() - (to - from); ctrl->Replace(from, to, textToInsert); ctrl->SetSelectionNStart(i, from + textToInsert.length()); ctrl->SetSelectionNEnd(i, from + textToInsert.length()); } } else { ctrl->ReplaceSelection(textToInsert); if(!userProvidedSignature || (!funcSig.IsEmpty() && (funcSig != "()"))) { // Place the caret between the parenthesis int caretPos(wxNOT_FOUND); if(moveCaretLeft) { caretPos = start + textToInsert.length() - 1; } else if(moveCaretRight) { // Move the caret one char to the right caretPos = start + textToInsert.length() + 1; } else { caretPos = start + textToInsert.length(); } ctrl->SetCurrentPos(caretPos); ctrl->SetSelection(caretPos, caretPos); // trigger a code complete for function calltip. // We do this by simply mimicing the user action of going to the menubar: // Edit->Display Function Calltip wxCommandEvent event(wxEVT_MENU, XRCID("function_call_tip")); wxTheApp->GetTopWindow()->GetEventHandler()->AddPendingEvent(event); } } } else { if(!ranges.empty()) { // Multiple carets int offset = 0; for(size_t i = 0; i < ranges.size(); ++i) { int from = ranges.at(i).first; int to = ranges.at(i).second; from += offset; to += offset; // Once we enter that text into the editor, it will change the original // offsets (in most cases the entered text is larger than that typed text) offset += entryText.length() - (to - from); ctrl->Replace(from, to, entryText); ctrl->SetSelectionNStart(i, from + entryText.length()); ctrl->SetSelectionNEnd(i, from + entryText.length()); } } else { // Default ctrl->ReplaceSelection(entryText); } } } }