// Scintilla source code edit control /** @file ScintillaBase.cxx ** An enhanced subclass of Editor with calltips, autocomplete and context menu. **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include "Platform.h" #include "ILexer.h" #include "Scintilla.h" #ifdef SCI_LEXER #include "SciLexer.h" #endif #include "PropSetSimple.h" #ifdef SCI_LEXER #include "LexerModule.h" #include "Catalogue.h" #endif #include "Position.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "ContractionState.h" #include "CellBuffer.h" #include "CallTip.h" #include "KeyMap.h" #include "Indicator.h" #include "XPM.h" #include "LineMarker.h" #include "Style.h" #include "ViewStyle.h" #include "CharClassify.h" #include "Decoration.h" #include "CaseFolder.h" #include "Document.h" #include "Selection.h" #include "PositionCache.h" #include "EditModel.h" #include "MarginView.h" #include "EditView.h" #include "Editor.h" #include "AutoComplete.h" #include "ScintillaBase.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif ScintillaBase::ScintillaBase() { displayPopupMenu = true; listType = 0; maxListWidth = 0; multiAutoCMode = SC_MULTIAUTOC_ONCE; } ScintillaBase::~ScintillaBase() { } void ScintillaBase::Finalise() { Editor::Finalise(); popup.Destroy(); } void ScintillaBase::AddCharUTF(const char *s, unsigned int len, bool treatAsDBCS) { bool isFillUp = ac.Active() && ac.IsFillUpChar(*s); if (!isFillUp) { Editor::AddCharUTF(s, len, treatAsDBCS); } if (ac.Active()) { AutoCompleteCharacterAdded(s[0]); // For fill ups add the character after the autocompletion has // triggered so containers see the key so can display a calltip. if (isFillUp) { Editor::AddCharUTF(s, len, treatAsDBCS); } } } void ScintillaBase::Command(int cmdId) { switch (cmdId) { case idAutoComplete: // Nothing to do break; case idCallTip: // Nothing to do break; case idcmdUndo: WndProc(SCI_UNDO, 0, 0); break; case idcmdRedo: WndProc(SCI_REDO, 0, 0); break; case idcmdCut: WndProc(SCI_CUT, 0, 0); break; case idcmdCopy: WndProc(SCI_COPY, 0, 0); break; case idcmdPaste: WndProc(SCI_PASTE, 0, 0); break; case idcmdDelete: WndProc(SCI_CLEAR, 0, 0); break; case idcmdSelectAll: WndProc(SCI_SELECTALL, 0, 0); break; } } int ScintillaBase::KeyCommand(unsigned int iMessage) { // Most key commands cancel autocompletion mode if (ac.Active()) { switch (iMessage) { // Except for these case SCI_LINEDOWN: AutoCompleteMove(1); return 0; case SCI_LINEUP: AutoCompleteMove(-1); return 0; case SCI_PAGEDOWN: AutoCompleteMove(ac.lb->GetVisibleRows()); return 0; case SCI_PAGEUP: AutoCompleteMove(-ac.lb->GetVisibleRows()); return 0; case SCI_VCHOME: AutoCompleteMove(-5000); return 0; case SCI_LINEEND: AutoCompleteMove(5000); return 0; case SCI_DELETEBACK: DelCharBack(true); AutoCompleteCharacterDeleted(); EnsureCaretVisible(); return 0; case SCI_DELETEBACKNOTLINE: DelCharBack(false); AutoCompleteCharacterDeleted(); EnsureCaretVisible(); return 0; case SCI_TAB: AutoCompleteCompleted(0, SC_AC_TAB); return 0; case SCI_NEWLINE: AutoCompleteCompleted(0, SC_AC_NEWLINE); return 0; default: AutoCompleteCancel(); } } if (ct.inCallTipMode) { if ( (iMessage != SCI_CHARLEFT) && (iMessage != SCI_CHARLEFTEXTEND) && (iMessage != SCI_CHARRIGHT) && (iMessage != SCI_CHARRIGHTEXTEND) && (iMessage != SCI_EDITTOGGLEOVERTYPE) && (iMessage != SCI_DELETEBACK) && (iMessage != SCI_DELETEBACKNOTLINE) ) { ct.CallTipCancel(); } if ((iMessage == SCI_DELETEBACK) || (iMessage == SCI_DELETEBACKNOTLINE)) { if (sel.MainCaret() <= ct.posStartCallTip) { ct.CallTipCancel(); } } } return Editor::KeyCommand(iMessage); } void ScintillaBase::AutoCompleteDoubleClick(void *p) { ScintillaBase *sci = reinterpret_cast(p); sci->AutoCompleteCompleted(0, SC_AC_DOUBLECLICK); } void ScintillaBase::AutoCompleteInsert(Position startPos, int removeLen, const char *text, int textLen) { UndoGroup ug(pdoc); if (multiAutoCMode == SC_MULTIAUTOC_ONCE) { pdoc->DeleteChars(startPos, removeLen); const int lengthInserted = pdoc->InsertString(startPos, text, textLen); SetEmptySelection(startPos + lengthInserted); } else { // SC_MULTIAUTOC_EACH for (size_t r=0; r= 0) { positionInsert -= removeLen; pdoc->DeleteChars(positionInsert, removeLen); } const int lengthInserted = pdoc->InsertString(positionInsert, text, textLen); if (lengthInserted > 0) { sel.Range(r).caret.SetPosition(positionInsert + lengthInserted); sel.Range(r).anchor.SetPosition(positionInsert + lengthInserted); } sel.Range(r).ClearVirtualSpace(); } } } } void ScintillaBase::AutoCompleteStart(int lenEntered, const char *list) { //Platform::DebugPrintf("AutoComplete %s\n", list); ct.CallTipCancel(); if (ac.chooseSingle && (listType == 0)) { if (list && !strchr(list, ac.GetSeparator())) { const char *typeSep = strchr(list, ac.GetTypesep()); int lenInsert = typeSep ? static_cast(typeSep-list) : static_cast(strlen(list)); if (ac.ignoreCase) { // May need to convert the case before invocation, so remove lenEntered characters AutoCompleteInsert(sel.MainCaret() - lenEntered, lenEntered, list, lenInsert); } else { AutoCompleteInsert(sel.MainCaret(), 0, list + lenEntered, lenInsert - lenEntered); } ac.Cancel(); return; } } ac.Start(wMain, idAutoComplete, sel.MainCaret(), PointMainCaret(), lenEntered, vs.lineHeight, IsUnicodeMode(), technology); PRectangle rcClient = GetClientRectangle(); Point pt = LocationFromPosition(sel.MainCaret() - lenEntered); PRectangle rcPopupBounds = wMain.GetMonitorRect(pt); if (rcPopupBounds.Height() == 0) rcPopupBounds = rcClient; int heightLB = ac.heightLBDefault; int widthLB = ac.widthLBDefault; if (pt.x >= rcClient.right - widthLB) { HorizontalScrollTo(static_cast(xOffset + pt.x - rcClient.right + widthLB)); Redraw(); pt = PointMainCaret(); } if (wMargin.GetID()) { Point ptOrigin = GetVisibleOriginInMain(); pt.x += ptOrigin.x; pt.y += ptOrigin.y; } PRectangle rcac; rcac.left = pt.x - ac.lb->CaretFromEdge(); if (pt.y >= rcPopupBounds.bottom - heightLB && // Wont fit below. pt.y >= (rcPopupBounds.bottom + rcPopupBounds.top) / 2) { // and there is more room above. rcac.top = pt.y - heightLB; if (rcac.top < rcPopupBounds.top) { heightLB -= static_cast(rcPopupBounds.top - rcac.top); rcac.top = rcPopupBounds.top; } } else { rcac.top = pt.y + vs.lineHeight; } rcac.right = rcac.left + widthLB; rcac.bottom = static_cast(Platform::Minimum(static_cast(rcac.top) + heightLB, static_cast(rcPopupBounds.bottom))); ac.lb->SetPositionRelative(rcac, wMain); ac.lb->SetFont(vs.styles[STYLE_DEFAULT].font); unsigned int aveCharWidth = static_cast(vs.styles[STYLE_DEFAULT].aveCharWidth); ac.lb->SetAverageCharWidth(aveCharWidth); ac.lb->SetDoubleClickAction(AutoCompleteDoubleClick, this); ac.SetList(list ? list : ""); // Fiddle the position of the list so it is right next to the target and wide enough for all its strings PRectangle rcList = ac.lb->GetDesiredRect(); int heightAlloced = static_cast(rcList.bottom - rcList.top); widthLB = Platform::Maximum(widthLB, static_cast(rcList.right - rcList.left)); if (maxListWidth != 0) widthLB = Platform::Minimum(widthLB, aveCharWidth*maxListWidth); // Make an allowance for large strings in list rcList.left = pt.x - ac.lb->CaretFromEdge(); rcList.right = rcList.left + widthLB; if (((pt.y + vs.lineHeight) >= (rcPopupBounds.bottom - heightAlloced)) && // Wont fit below. ((pt.y + vs.lineHeight / 2) >= (rcPopupBounds.bottom + rcPopupBounds.top) / 2)) { // and there is more room above. rcList.top = pt.y - heightAlloced; } else { rcList.top = pt.y + vs.lineHeight; } rcList.bottom = rcList.top + heightAlloced; ac.lb->SetPositionRelative(rcList, wMain); ac.Show(true); if (lenEntered != 0) { AutoCompleteMoveToCurrentWord(); } } void ScintillaBase::AutoCompleteCancel() { if (ac.Active()) { SCNotification scn = {}; scn.nmhdr.code = SCN_AUTOCCANCELLED; scn.wParam = 0; scn.listType = 0; NotifyParent(scn); } ac.Cancel(); } void ScintillaBase::AutoCompleteMove(int delta) { ac.Move(delta); } void ScintillaBase::AutoCompleteMoveToCurrentWord() { std::string wordCurrent = RangeText(ac.posStart - ac.startLen, sel.MainCaret()); ac.Select(wordCurrent.c_str()); } void ScintillaBase::AutoCompleteCharacterAdded(char ch) { if (ac.IsFillUpChar(ch)) { AutoCompleteCompleted(ch, SC_AC_FILLUP); } else if (ac.IsStopChar(ch)) { AutoCompleteCancel(); } else { AutoCompleteMoveToCurrentWord(); } } void ScintillaBase::AutoCompleteCharacterDeleted() { if (sel.MainCaret() < ac.posStart - ac.startLen) { AutoCompleteCancel(); } else if (ac.cancelAtStartPos && (sel.MainCaret() <= ac.posStart)) { AutoCompleteCancel(); } else { AutoCompleteMoveToCurrentWord(); } SCNotification scn = {}; scn.nmhdr.code = SCN_AUTOCCHARDELETED; scn.wParam = 0; scn.listType = 0; NotifyParent(scn); } void ScintillaBase::AutoCompleteCompleted(char ch, unsigned int completionMethod) { int item = ac.GetSelection(); if (item == -1) { AutoCompleteCancel(); return; } const std::string selected = ac.GetValue(item); ac.Show(false); SCNotification scn = {}; scn.nmhdr.code = listType > 0 ? SCN_USERLISTSELECTION : SCN_AUTOCSELECTION; scn.message = 0; scn.ch = ch; scn.listCompletionMethod = completionMethod; scn.wParam = listType; scn.listType = listType; Position firstPos = ac.posStart - ac.startLen; scn.position = firstPos; scn.lParam = firstPos; scn.text = selected.c_str(); NotifyParent(scn); if (!ac.Active()) return; ac.Cancel(); if (listType > 0) return; Position endPos = sel.MainCaret(); if (ac.dropRestOfWord) endPos = pdoc->ExtendWordSelect(endPos, 1, true); if (endPos < firstPos) return; AutoCompleteInsert(firstPos, endPos - firstPos, selected.c_str(), static_cast(selected.length())); SetLastXChosen(); scn.nmhdr.code = SCN_AUTOCCOMPLETED; NotifyParent(scn); } int ScintillaBase::AutoCompleteGetCurrent() const { if (!ac.Active()) return -1; return ac.GetSelection(); } int ScintillaBase::AutoCompleteGetCurrentText(char *buffer) const { if (ac.Active()) { int item = ac.GetSelection(); if (item != -1) { const std::string selected = ac.GetValue(item); if (buffer != NULL) memcpy(buffer, selected.c_str(), selected.length()+1); return static_cast(selected.length()); } } if (buffer != NULL) *buffer = '\0'; return 0; } void ScintillaBase::CallTipShow(Point pt, const char *defn) { ac.Cancel(); // If container knows about STYLE_CALLTIP then use it in place of the // STYLE_DEFAULT for the face name, size and character set. Also use it // for the foreground and background colour. int ctStyle = ct.UseStyleCallTip() ? STYLE_CALLTIP : STYLE_DEFAULT; if (ct.UseStyleCallTip()) { ct.SetForeBack(vs.styles[STYLE_CALLTIP].fore, vs.styles[STYLE_CALLTIP].back); } if (wMargin.GetID()) { Point ptOrigin = GetVisibleOriginInMain(); pt.x += ptOrigin.x; pt.y += ptOrigin.y; } PRectangle rc = ct.CallTipStart(sel.MainCaret(), pt, vs.lineHeight, defn, vs.styles[ctStyle].fontName, vs.styles[ctStyle].sizeZoomed, CodePage(), vs.styles[ctStyle].characterSet, vs.technology, wMain); // If the call-tip window would be out of the client // space PRectangle rcClient = GetClientRectangle(); int offset = vs.lineHeight + static_cast(rc.Height()); // adjust so it displays above the text. if (rc.bottom > rcClient.bottom && rc.Height() < rcClient.Height()) { rc.top -= offset; rc.bottom -= offset; } // adjust so it displays below the text. if (rc.top < rcClient.top && rc.Height() < rcClient.Height()) { rc.top += offset; rc.bottom += offset; } // Now display the window. CreateCallTipWindow(rc); ct.wCallTip.SetPositionRelative(rc, wMain); ct.wCallTip.Show(); } void ScintillaBase::CallTipClick() { SCNotification scn = {}; scn.nmhdr.code = SCN_CALLTIPCLICK; scn.position = ct.clickPlace; NotifyParent(scn); } void ScintillaBase::ContextMenu(Point pt) { if (displayPopupMenu) { bool writable = !WndProc(SCI_GETREADONLY, 0, 0); popup.CreatePopUp(); AddToPopUp("Undo", idcmdUndo, writable && pdoc->CanUndo()); AddToPopUp("Redo", idcmdRedo, writable && pdoc->CanRedo()); AddToPopUp(""); AddToPopUp("Cut", idcmdCut, writable && !sel.Empty()); AddToPopUp("Copy", idcmdCopy, !sel.Empty()); AddToPopUp("Paste", idcmdPaste, writable && WndProc(SCI_CANPASTE, 0, 0)); AddToPopUp("Delete", idcmdDelete, writable && !sel.Empty()); AddToPopUp(""); AddToPopUp("Select All", idcmdSelectAll); popup.Show(pt, wMain); } } void ScintillaBase::CancelModes() { AutoCompleteCancel(); ct.CallTipCancel(); Editor::CancelModes(); } void ScintillaBase::ButtonDownWithModifiers(Point pt, unsigned int curTime, int modifiers) { CancelModes(); Editor::ButtonDownWithModifiers(pt, curTime, modifiers); } void ScintillaBase::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) { ButtonDownWithModifiers(pt, curTime, ModifierFlags(shift, ctrl, alt)); } #ifdef SCI_LEXER #ifdef SCI_NAMESPACE namespace Scintilla { #endif class LexState : public LexInterface { const LexerModule *lexCurrent; void SetLexerModule(const LexerModule *lex); PropSetSimple props; int interfaceVersion; public: int lexLanguage; explicit LexState(Document *pdoc_); virtual ~LexState(); void SetLexer(uptr_t wParam); void SetLexerLanguage(const char *languageName); const char *DescribeWordListSets(); void SetWordList(int n, const char *wl); const char *GetName() const; void *PrivateCall(int operation, void *pointer); const char *PropertyNames(); int PropertyType(const char *name); const char *DescribeProperty(const char *name); void PropSet(const char *key, const char *val); const char *PropGet(const char *key) const; int PropGetInt(const char *key, int defaultValue=0) const; int PropGetExpanded(const char *key, char *result) const; int LineEndTypesSupported(); int AllocateSubStyles(int styleBase, int numberStyles); int SubStylesStart(int styleBase); int SubStylesLength(int styleBase); int StyleFromSubStyle(int subStyle); int PrimaryStyleFromStyle(int style); void FreeSubStyles(); void SetIdentifiers(int style, const char *identifiers); int DistanceToSecondaryStyles(); const char *GetSubStyleBases(); }; #ifdef SCI_NAMESPACE } #endif LexState::LexState(Document *pdoc_) : LexInterface(pdoc_) { lexCurrent = 0; performingStyle = false; interfaceVersion = lvOriginal; lexLanguage = SCLEX_CONTAINER; } LexState::~LexState() { if (instance) { instance->Release(); instance = 0; } } LexState *ScintillaBase::DocumentLexState() { if (!pdoc->pli) { pdoc->pli = new LexState(pdoc); } return static_cast(pdoc->pli); } void LexState::SetLexerModule(const LexerModule *lex) { if (lex != lexCurrent) { if (instance) { instance->Release(); instance = 0; } interfaceVersion = lvOriginal; lexCurrent = lex; if (lexCurrent) { instance = lexCurrent->Create(); interfaceVersion = instance->Version(); } pdoc->LexerChanged(); } } void LexState::SetLexer(uptr_t wParam) { lexLanguage = static_cast(wParam); if (lexLanguage == SCLEX_CONTAINER) { SetLexerModule(0); } else { const LexerModule *lex = Catalogue::Find(lexLanguage); if (!lex) lex = Catalogue::Find(SCLEX_NULL); SetLexerModule(lex); } } void LexState::SeHTTP/1.1 200 OK Connection: keep-alive Connection: keep-alive Content-Disposition: inline; filename="ScintillaBase.cxx" Content-Disposition: inline; filename="ScintillaBase.cxx" Content-Length: 28272 Content-Length: 28272 Content-Security-Policy: default-src 'none' Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Type: text/plain; charset=UTF-8 Date: Sun, 19 Oct 2025 13:40:06 UTC ETag: "cb1be4214afbd5e3c545cb48cdd32b7acaf063a1" ETag: "cb1be4214afbd5e3c545cb48cdd32b7acaf063a1" Expires: Wed, 17 Oct 2035 13:40:06 GMT Expires: Wed, 17 Oct 2035 13:40:06 GMT Last-Modified: Sun, 19 Oct 2025 13:40:06 GMT Last-Modified: Sun, 19 Oct 2025 13:40:06 GMT Server: OpenBSD httpd Server: OpenBSD httpd X-Content-Type-Options: nosniff X-Content-Type-Options: nosniff // Scintilla source code edit control /** @file ScintillaBase.cxx ** An enhanced subclass of Editor with calltips, autocomplete and context menu. **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include "Platform.h" #include "ILexer.h" #include "Scintilla.h" #ifdef SCI_LEXER #include "SciLexer.h" #endif #include "PropSetSimple.h" #ifdef SCI_LEXER #include "LexerModule.h" #include "Catalogue.h" #endif #include "Position.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "ContractionState.h" #include "CellBuffer.h" #include "CallTip.h" #include "KeyMap.h" #include "Indicator.h" #include "XPM.h" #include "LineMarker.h" #include "Style.h" #include "ViewStyle.h" #include "CharClassify.h" #include "Decoration.h" #include "CaseFolder.h" #include "Document.h" #include "Selection.h" #include "PositionCache.h" #include "EditModel.h" #include "MarginView.h" #include "EditView.h" #include "Editor.h" #include "AutoComplete.h" #include "ScintillaBase.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif ScintillaBase::ScintillaBase() { displayPopupMenu = true; listType = 0; maxListWidth = 0; multiAutoCMode = SC_MULTIAUTOC_ONCE; } ScintillaBase::~ScintillaBase() { } void ScintillaBase::Finalise() { Editor::Finalise(); popup.Destroy(); } void ScintillaBase::AddCharUTF(const char *s, unsigned int len, bool treatAsDBCS) { bool isFillUp = ac.Active() && ac.IsFillUpChar(*s); if (!isFillUp) { Editor::AddCharUTF(s, len, treatAsDBCS); } if (ac.Active()) { AutoCompleteCharacterAdded(s[0]); // For fill ups add the character after the autocompletion has // triggered so containers see the key so can display a calltip. if (isFillUp) { Editor::AddCharUTF(s, len, treatAsDBCS); } } } void ScintillaBase::Command(int cmdId) { switch (cmdId) { case idAutoComplete: // Nothing to do break; case idCallTip: // Nothing to do break; case idcmdUndo: WndProc(SCI_UNDO, 0, 0); break; case idcmdRedo: WndProc(SCI_REDO, 0, 0); break; case idcmdCut: WndProc(SCI_CUT, 0, 0); break; case idcmdCopy: WndProc(SCI_COPY, 0, 0); break; case idcmdPaste: WndProc(SCI_PASTE, 0, 0); break; case idcmdDelete: WndProc(SCI_CLEAR, 0, 0); break; case idcmdSelectAll: WndProc(SCI_SELECTALL, 0, 0); break; } } int ScintillaBase::KeyCommand(unsigned int iMessage) { // Most key commands cancel autocompletion mode if (ac.Active()) { switch (iMessage) { // Except for these case SCI_LINEDOWN: AutoCompleteMove(1); return 0; case SCI_LINEUP: AutoCompleteMove(-1); return 0; case SCI_PAGEDOWN: AutoCompleteMove(ac.lb->GetVisibleRows()); return 0; case SCI_PAGEUP: AutoCompleteMove(-ac.lb->GetVisibleRows()); return 0; case SCI_VCHOME: AutoCompleteMove(-5000); return 0; case SCI_LINEEND: AutoCompleteMove(5000); return 0; case SCI_DELETEBACK: DelCharBack(true); AutoCompleteCharacterDeleted(); EnsureCaretVisible(); return 0; case SCI_DELETEBACKNOTLINE: DelCharBack(false); AutoCompleteCharacterDeleted(); EnsureCaretVisible(); return 0; case SCI_TAB: AutoCompleteCompleted(0, SC_AC_TAB); return 0; case SCI_NEWLINE: AutoCompleteCompleted(0, SC_AC_NEWLINE); return 0; default: AutoCompleteCancel(); } } if (ct.inCallTipMode) { if ( (iMessage != SCI_CHARLEFT) && (iMessage != SCI_CHARLEFTEXTEND) && (iMessage != SCI_CHARRIGHT) && (iMessage != SCI_CHARRIGHTEXTEND) && (iMessage != SCI_EDITTOGGLEOVERTYPE) && (iMessage != SCI_DELETEBACK) && (iMessage != SCI_DELETEBACKNOTLINE) ) { ct.CallTipCancel(); } if ((iMessage == SCI_DELETEBACK) || (iMessage == SCI_DELETEBACKNOTLINE)) { if (sel.MainCaret() <= ct.posStartCallTip) { ct.CallTipCancel(); } } } return Editor::KeyCommand(iMessage); } void ScintillaBase::AutoCompleteDoubleClick(void *p) { ScintillaBase *sci = reinterpret_cast(p); sci->AutoCompleteCompleted(0, SC_AC_DOUBLECLICK); } void ScintillaBase::AutoCompleteInsert(Position startPos, int removeLen, const char *text, int textLen) { UndoGroup ug(pdoc); if (multiAutoCMode == SC_MULTIAUTOC_ONCE) { pdoc->DeleteChars(startPos, removeLen); const int lengthInserted = pdoc->InsertString(startPos, text, textLen); SetEmptySelection(startPos + lengthInserted); } else { // SC_MULTIAUTOC_EACH for (size_t r=0; r= 0) { positionInsert -= removeLen; pdoc->DeleteChars(positionInsert, removeLen); } const int lengthInserted = pdoc->InsertString(positionInsert, text, textLen); if (lengthInserted > 0) { sel.Range(r).caret.SetPosition(positionInsert + lengthInserted); sel.Range(r).anchor.SetPosition(positionInsert + lengthInserted); } sel.Range(r).ClearVirtualSpace(); } } } } void ScintillaBase::AutoCompleteStart(int lenEntered, const char *list) { //Platform::DebugPrintf("AutoComplete %s\n", list); ct.CallTipCancel(); if (ac.chooseSingle && (listType == 0)) { if (list && !strchr(list, ac.GetSeparator())) { const char *typeSep = strchr(list, ac.GetTypesep()); int lenInsert = typeSep ? static_cast(typeSep-list) : static_cast(strlen(list)); if (ac.ignoreCase) { // May need to convert the case before invocation, so remove lenEntered characters AutoCompleteInsert(sel.MainCaret() - lenEntered, lenEntered, list, lenInsert); } else { AutoCompleteInsert(sel.MainCaret(), 0, list + lenEntered, lenInsert - lenEntered); } ac.Cancel(); return; } } ac.Start(wMain, idAutoComplete, sel.MainCaret(), PointMainCaret(), lenEntered, vs.lineHeight, IsUnicodeMode(), technology); PRectangle rcClient = GetClientRectangle(); Point pt = LocationFromPosition(sel.MainCaret() - lenEntered); PRectangle rcPopupBounds = wMain.GetMonitorRect(pt); if (rcPopupBounds.Height() == 0) rcPopupBounds = rcClient; int heightLB = ac.heightLBDefault; int widthLB = ac.widthLBDefault; if (pt.x >= rcClient.right - widthLB) { HorizontalScrollTo(static_cast(xOffset + pt.x - rcClient.right + widthLB)); Redraw(); pt = PointMainCaret(); } if (wMargin.GetID()) { Point ptOrigin = GetVisibleOriginInMain(); pt.x += ptOrigin.x; pt.y += ptOrigin.y; } PRectangle rcac; rcac.left = pt.x - ac.lb->CaretFromEdge(); if (pt.y >= rcPopupBounds.bottom - heightLB && // Wont fit below. pt.y >= (rcPopupBounds.bottom + rcPopupBounds.top) / 2) { // and there is more room above. rcac.top = pt.y - heightLB; if (rcac.top < rcPopupBounds.top) { heightLB -= static_cast(rcPopupBounds.top - rcac.top); rcac.top = rcPopupBounds.top; } } else { rcac.top = pt.y + vs.lineHeight; } rcac.right = rcac.left + widthLB; rcac.bottom = static_cast(Platform::Minimum(static_cast(rcac.top) + heightLB, static_cast(rcPopupBounds.bottom))); ac.lb->SetPositionRelative(rcac, wMain); ac.lb->SetFont(vs.styles[STYLE_DEFAULT].font); unsigned int aveCharWidth = static_cast(vs.styles[STYLE_DEFAULT].aveCharWidth); ac.lb->SetAverageCharWidth(aveCharWidth); ac.lb->SetDoubleClickAction(AutoCompleteDoubleClick, this); ac.SetList(list ? list : ""); // Fiddle the position of the list so it is right next to the target and wide enough for all its strings PRectangle rcList = ac.lb->GetDesiredRect(); int heightAlloced = static_cast(rcList.bottom - rcList.top); widthLB = Platform::Maximum(widthLB, static_cast(rcList.right - rcList.left)); if (maxListWidth != 0) widthLB = Platform::Minimum(widthLB, aveCharWidth*maxListWidth); // Make an allowance for large strings in list rcList.left = pt.x - ac.lb->CaretFromEdge(); rcList.right = rcList.left + widthLB; if (((pt.y + vs.lineHeight) >= (rcPopupBounds.bottom - heightAlloced)) && // Wont fit below. ((pt.y + vs.lineHeight / 2) >= (rcPopupBounds.bottom + rcPopupBounds.top) / 2)) { // and there is more room above. rcList.top = pt.y - heightAlloced; } else { rcList.top = pt.y + vs.lineHeight; } rcList.bottom = rcList.top + heightAlloced; ac.lb->SetPositionRelative(rcList, wMain); ac.Show(true); if (lenEntered != 0) { AutoCompleteMoveToCurrentWord(); } } void ScintillaBase::AutoCompleteCancel() { if (ac.Active()) { SCNotification scn = {}; scn.nmhdr.code = SCN_AUTOCCANCELLED; scn.wParam = 0; scn.listType = 0; NotifyParent(scn); } ac.Cancel(); } void ScintillaBase::AutoCompleteMove(int delta) { ac.Move(delta); } void ScintillaBase::AutoCompleteMoveToCurrentWord() { std::string wordCurrent = RangeText(ac.posStart - ac.startLen, sel.MainCaret()); ac.Select(wordCurrent.c_str()); } void ScintillaBase::AutoCompleteCharacterAdded(char ch) { if (ac.IsFillUpChar(ch)) { AutoCompleteCompleted(ch, SC_AC_FILLUP); } else if (ac.IsStopChar(ch)) { AutoCompleteCancel(); } else { AutoCompleteMoveToCurrentWord(); } } void ScintillaBase::AutoCompleteCharacterDeleted() { if (sel.MainCaret() < ac.posStart - ac.startLen) { AutoCompleteCancel(); } else if (ac.cancelAtStartPos && (sel.MainCaret() <= ac.posStart)) { AutoCompleteCancel(); } else { AutoCompleteMoveToCurrentWord(); } SCNotification scn = {}; scn.nmhdr.code = SCN_AUTOCCHARDELETED; scn.wParam = 0; scn.listType = 0; NotifyParent(scn); } void ScintillaBase::AutoCompleteCompleted(char ch, unsigned int completionMethod) { int item = ac.GetSelection(); if (item == -1) { AutoCompleteCancel(); return; } const std::string selected = ac.GetValue(item); ac.Show(false); SCNotification scn = {}; scn.nmhdr.code = listType > 0 ? SCN_USERLISTSELECTION : SCN_AUTOCSELECTION; scn.message = 0; scn.ch = ch; scn.listCompletionMethod = completionMethod; scn.wParam = listType; scn.listType = listType; Position firstPos = ac.posStart - ac.startLen; scn.position = firstPos; scn.lParam = firstPos; scn.text = selected.c_str(); NotifyParent(scn); if (!ac.Active()) return; ac.Cancel(); if (listType > 0) return; Position endPos = sel.MainCaret(); if (ac.dropRestOfWord) endPos = pdoc->ExtendWordSelect(endPos, 1, true); if (endPos < firstPos) return; AutoCompleteInsert(firstPos, endPos - firstPos, selected.c_str(), static_cast(selected.length())); SetLastXChosen(); scn.nmhdr.code = SCN_AUTOCCOMPLETED; NotifyParent(scn); } int ScintillaBase::AutoCompleteGetCurrent() const { if (!ac.Active()) return -1; return ac.GetSelection(); } int ScintillaBase::