// Scintilla source code edit control /** @file ScintillaBase.cxx ** An enhanced subclass of Editor with calltips, autocomplete and context menu. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include "Platform.h" #include "Scintilla.h" #include "PropSet.h" #ifdef SCI_LEXER #include "SciLexer.h" #include "Accessor.h" #include "DocumentAccessor.h" #include "KeyWords.h" #endif #include "ContractionState.h" #include "SVector.h" #include "CellBuffer.h" #include "CallTip.h" #include "KeyMap.h" #include "Indicator.h" #include "LineMarker.h" #include "Style.h" #include "ViewStyle.h" #include "AutoComplete.h" #include "Document.h" #include "Editor.h" #include "ScintillaBase.h" ScintillaBase::ScintillaBase() { listType = 0; #ifdef SCI_LEXER lexLanguage = SCLEX_CONTAINER; lexCurrent = 0; for (int wl = 0;wl < numWordLists;wl++) keyWordLists[wl] = new WordList; keyWordLists[numWordLists] = 0; #endif } ScintillaBase::~ScintillaBase() { #ifdef SCI_LEXER for (int wl = 0;wl < numWordLists;wl++) delete keyWordLists[wl]; #endif } void ScintillaBase::Finalise() { Editor::Finalise(); popup.Destroy(); } void ScintillaBase::RefreshColourPalette(Palette &pal, bool want) { Editor::RefreshColourPalette(pal, want); ct.RefreshColourPalette(pal, want); } void ScintillaBase::AddCharUTF(char *s, unsigned int len) { bool acActiveBeforeCharAdded = ac.Active(); if (!acActiveBeforeCharAdded || !ac.IsFillUpChar(*s)) Editor::AddCharUTF(s, len); if (acActiveBeforeCharAdded) AutoCompleteChanged(s[0]); } 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(5); return 0; case SCI_PAGEUP: AutoCompleteMove( -5); return 0; case SCI_VCHOME: AutoCompleteMove( -5000); return 0; case SCI_LINEEND: AutoCompleteMove(5000); return 0; case SCI_DELETEBACK: DelCharBack(); AutoCompleteChanged(); EnsureCaretVisible(); return 0; case SCI_TAB: AutoCompleteCompleted(); return 0; case SCI_NEWLINE: AutoCompleteCompleted(); return 0; default: ac.Cancel(); } } if (ct.inCallTipMode) { if ( (iMessage != SCI_CHARLEFT) && (iMessage != SCI_CHARLEFTEXTEND) && (iMessage != SCI_CHARRIGHT) && (iMessage != SCI_CHARLEFTEXTEND) && (iMessage != SCI_EDITTOGGLEOVERTYPE) && (iMessage != SCI_DELETEBACK) ) { ct.CallTipCancel(); } if (iMessage == SCI_DELETEBACK) { if (currentPos <= ct.posStartCallTip) { ct.CallTipCancel(); } } } return Editor::KeyCommand(iMessage); } 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())) { if (ac.ignoreCase) { SetEmptySelection(currentPos - lenEntered); pdoc->DeleteChars(currentPos, lenEntered); SetEmptySelection(currentPos); pdoc->InsertString(currentPos, list); SetEmptySelection(currentPos + strlen(list)); } else { SetEmptySelection(currentPos); pdoc->InsertString(currentPos, list + lenEntered); SetEmptySelection(currentPos + strlen(list + lenEntered)); } return ; } } ac.Start(wMain, idAutoComplete, currentPos, lenEntered); PRectangle rcClient = GetClientRectangle(); Point pt = LocationFromPosition(currentPos - lenEntered); int heightLB = 100; int widthLB = 100; if (pt.x >= rcClient.right - widthLB) { HorizontalScrollTo(xOffset + pt.x - rcClient.right + widthLB); Redraw(); pt = LocationFromPosition(currentPos); } PRectangle rcac; rcac.left = pt.x - 5; if (pt.y >= rcClient.bottom - heightLB && // Wont fit below. pt.y >= (rcClient.bottom + rcClient.top) / 2) { // and there is more room above. rcac.top = pt.y - heightLB; if (rcac.top < 0) { heightLB += rcac.top; rcac.top = 0; } } else { rcac.top = pt.y + vs.lineHeight; } rcac.right = rcac.left + widthLB; rcac.bottom = Platform::Minimum(rcac.top + heightLB, rcClient.bottom); ac.lb.SetPositionRelative(rcac, wMain); ac.lb.SetFont(vs.styles[STYLE_DEFAULT].font); ac.lb.SetAverageCharWidth(vs.styles[STYLE_DEFAULT].aveCharWidth); ac.SetList(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 = rcList.bottom - rcList.top; widthLB = Platform::Maximum(widthLB, rcList.right - rcList.left); // Make an allowance for large strings in list rcList.left = pt.x - 5; rcList.right = rcList.left + widthLB; if (pt.y >= rcClient.bottom - heightLB && // Wont fit below. pt.y >= (rcClient.bottom + rcClient.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(); if (lenEntered != 0) { AutoCompleteMoveToCurrentWord(); } } void ScintillaBase::AutoCompleteCancel() { ac.Cancel(); } void ScintillaBase::AutoCompleteMove(int delta) { ac.Move(delta); } void ScintillaBase::AutoCompleteMoveToCurrentWord() { char wordCurrent[1000]; int i; int startWord = ac.posStart - ac.startLen; for (i = startWord; i < currentPos; i++) wordCurrent[i - startWord] = pdoc->CharAt(i); wordCurrent[i - startWord] = '\0'; ac.Select(wordCurrent); } void ScintillaBase::AutoCompleteChanged(char ch) { if (ac.IsFillUpChar(ch)) { AutoCompleteCompleted(ch); } else if (currentPos <= ac.posStart - ac.startLen) { ac.Cancel(); } else if (ac.cancelAtStartPos && currentPos <= ac.posStart) { ac.Cancel(); } else if (ac.IsStopChar(ch)) { ac.Cancel(); } else { AutoCompleteMoveToCurrentWord(); } } void ScintillaBase::AutoCompleteCompleted(char fillUp/*='\0'*/) { int item = ac.lb.GetSelection(); char selected[1000]; if (item != -1) { ac.lb.GetValue(item, selected, sizeof(selected)); } ac.Cancel(); if (listType > 0) { userListSelected = selected; SCNotification scn; scn.nmhdr.code = SCN_USERLISTSELECTION; scn.message = 0; scn.wParam = listType; scn.lParam = 0; scn.text = userListSelected.c_str(); NotifyParent(scn); return ; } Position firstPos = ac.posStart - ac.startLen; if (currentPos < firstPos) return ; if (currentPos != firstPos) { pdoc->DeleteChars(firstPos, currentPos - firstPos); } SetEmptySelection(ac.posStart); if (item != -1) { SString piece = selected; if (fillUp) piece += fillUp; pdoc->InsertString(firstPos, piece.c_str()); SetEmptySelection(firstPos + piece.length()); } } void ScintillaBase::ContextMenu(Point pt) { 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 && currentPos != anchor); AddToPopUp("Copy", idcmdCopy, currentPos != anchor); AddToPopUp("Paste", idcmdPaste, writable && WndProc(SCI_CANPASTE, 0, 0)); AddToPopUp("Delete", idcmdDelete, writable && currentPos != anchor); AddToPopUp(""); AddToPopUp("Select All", idcmdSelectAll); popup.Show(pt, wMain); } HTTP/1.1 200 OK Connection: keep-alive Connection: keep-alive Content-Disposition: inline; filename="ScintillaBase.cxx" Content-Disposition: inline; filename="ScintillaBase.cxx" Content-Length: 13459 Content-Length: 13459 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: Wed, 22 Oct 2025 11:32:16 UTC ETag: "707f59b9f440978ee0ea10dc1dd321d8bf22e40e" ETag: "707f59b9f440978ee0ea10dc1dd321d8bf22e40e" Expires: Sat, 20 Oct 2035 11:32:16 GMT Expires: Sat, 20 Oct 2035 11:32:16 GMT Last-Modified: Wed, 22 Oct 2025 11:32:16 GMT Last-Modified: Wed, 22 Oct 2025 11:32:16 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-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include "Platform.h" #include "Scintilla.h" #include "PropSet.h" #ifdef SCI_LEXER #include "SciLexer.h" #include "Accessor.h" #include "DocumentAccessor.h" #include "KeyWords.h" #endif #include "ContractionState.h" #include "SVector.h" #include "CellBuffer.h" #include "CallTip.h" #include "KeyMap.h" #include "Indicator.h" #include "LineMarker.h" #include "Style.h" #include "ViewStyle.h" #include "AutoComplete.h" #include "Document.h" #include "Editor.h" #include "ScintillaBase.h" ScintillaBase::ScintillaBase() { listType = 0; #ifdef SCI_LEXER lexLanguage = SCLEX_CONTAINER; lexCurrent = 0; for (int wl = 0;wl < numWordLists;wl++) keyWordLists[wl] = new WordList; keyWordLists[numWordLists] = 0; #endif } ScintillaBase::~ScintillaBase() { #ifdef SCI_LEXER for (int wl = 0;wl < numWordLists;wl++) delete keyWordLists[wl]; #endif } void ScintillaBase::Finalise() { Editor::Finalise(); popup.Destroy(); } void ScintillaBase::RefreshColourPalette(Palette &pal, bool want) { Editor::RefreshColourPalette(pal, want); ct.RefreshColourPalette(pal, want); } void ScintillaBase::AddCharUTF(char *s, unsigned int len) { bool acActiveBeforeCharAdded = ac.Active(); if (!acActiveBeforeCharAdded || !ac.IsFillUpChar(*s)) Editor::AddCharUTF(s, len); if (acActiveBeforeCharAdded) AutoCompleteChanged(s[0]); } 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(5); return 0; case SCI_PAGEUP: AutoCompleteMove( -5); return 0; case SCI_VCHOME: AutoCompleteMove( -5000); return 0; case SCI_LINEEND: AutoCompleteMove(5000); return 0; case SCI_DELETEBACK: DelCharBack(); AutoCompleteChanged(); EnsureCaretVisible(); return 0; case SCI_TAB: AutoCompleteCompleted(); return 0; case SCI_NEWLINE: AutoCompleteCompleted(); return 0; default: ac.Cancel(); } } if (ct.inCallTipMode) { if ( (iMessage != SCI_CHARLEFT) && (iMessage != SCI_CHARLEFTEXTEND) && (iMessage != SCI_CHARRIGHT) && (iMessage != SCI_CHARLEFTEXTEND) && (iMessage != SCI_EDITTOGGLEOVERTYPE) && (iMessage != SCI_DELETEBACK) ) { ct.CallTipCancel(); } if (iMessage == SCI_DELETEBACK) { if (currentPos <= ct.posStartCallTip) { ct.CallTipCancel(); } } } return Editor::KeyCommand(iMessage); } 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())) { if (ac.ignoreCase) { SetEmptySelection(currentPos - lenEntered); pdoc->DeleteChars(currentPos, lenEntered); SetEmptySelection(currentPos); pdoc->InsertString(currentPos, list); SetEmptySelection(currentPos + strlen(list)); } else { SetEmptySelection(currentPos); pdoc->InsertString(currentPos, list + lenEntered); SetEmptySelection(currentPos + strlen(list + lenEntered)); } return ; } } ac.Start(wMain, idAutoComplete, currentPos, lenEntered); PRectangle rcClient = GetClientRectangle(); Point pt = LocationFromPosition(currentPos - lenEntered); int heightLB = 100; int widthLB = 100; if (pt.x >= rcClient.right - widthLB) { Horizon