summaryrefslogtreecommitdiffstats
path: root/src/ScintillaBase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ScintillaBase.cpp')
-rwxr-xr-xsrc/ScintillaBase.cpp727
1 files changed, 727 insertions, 0 deletions
diff --git a/src/ScintillaBase.cpp b/src/ScintillaBase.cpp
new file mode 100755
index 0000000..bcb0a77
--- /dev/null
+++ b/src/ScintillaBase.cpp
@@ -0,0 +1,727 @@
+// 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 <neilh@scintilla.org>
+// The License.txt file describes the conditions under which this software may be distributed.
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#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 "XPM.h"
+#include "LineMarker.h"
+#include "Style.h"
+#include "ViewStyle.h"
+#include "AutoComplete.h"
+#include "CharClassify.h"
+#include "Document.h"
+#include "Editor.h"
+#include "ScintillaBase.h"
+
+ScintillaBase::ScintillaBase() {
+ displayPopupMenu = true;
+ listType = 0;
+ maxListWidth = 0;
+#ifdef SCI_LEXER
+ lexLanguage = SCLEX_CONTAINER;
+ performingStyle = false;
+ 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 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(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(true);
+ AutoCompleteCharacterDeleted();
+ EnsureCaretVisible();
+ return 0;
+ case SCI_DELETEBACKNOTLINE:
+ DelCharBack(false);
+ AutoCompleteCharacterDeleted();
+ 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) &&
+ (iMessage != SCI_DELETEBACKNOTLINE)
+ ) {
+ ct.CallTipCancel();
+ }
+ if ((iMessage == SCI_DELETEBACK) || (iMessage == SCI_DELETEBACKNOTLINE)) {
+ if (currentPos <= ct.posStartCallTip) {
+ ct.CallTipCancel();
+ }
+ }
+ }
+ return Editor::KeyCommand(iMessage);
+}
+
+void ScintillaBase::AutoCompleteDoubleClick(void* p) {
+ ScintillaBase* sci = reinterpret_cast<ScintillaBase*>(p);
+ sci->AutoCompleteCompleted();
+}
+
+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());
+ size_t lenInsert = (typeSep) ? (typeSep-list) : strlen(list);
+ if (ac.ignoreCase) {
+ SetEmptySelection(currentPos - lenEntered);
+ pdoc->DeleteChars(currentPos, lenEntered);
+ SetEmptySelection(currentPos);
+ pdoc->InsertString(currentPos, list, lenInsert);
+ SetEmptySelection(currentPos + lenInsert);
+ } else {
+ SetEmptySelection(currentPos);
+ pdoc->InsertString(currentPos, list + lenEntered, lenInsert - lenEntered);
+ SetEmptySelection(currentPos + lenInsert - lenEntered);
+ }
+ return;
+ }
+ }
+ ac.Start(wMain, idAutoComplete, currentPos, LocationFromPosition(currentPos),
+ lenEntered, vs.lineHeight, IsUnicodeMode());
+
+ 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 - ac.lb->CaretFromEdge();
+ 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);
+ unsigned int aveCharWidth = vs.styles[STYLE_DEFAULT].aveCharWidth;
+ ac.lb->SetAverageCharWidth(aveCharWidth);
+ ac.lb->SetDoubleClickAction(AutoCompleteDoubleClick, this);
+
+ 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);
+ 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) >= (rcClient.bottom - heightAlloced)) && // Wont fit below.
+ ((pt.y + vs.lineHeight / 2) >= (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(true);
+ 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 - startWord < 1000; i++)
+ wordCurrent[i - startWord] = pdoc->CharAt(i);
+ wordCurrent[Platform::Minimum(i - startWord, 999)] = '\0';
+ ac.Select(wordCurrent);
+}
+
+void ScintillaBase::AutoCompleteCharacterAdded(char ch) {
+ if (ac.IsFillUpChar(ch)) {
+ AutoCompleteCompleted();
+ } else if (ac.IsStopChar(ch)) {
+ ac.Cancel();
+ } else {
+ AutoCompleteMoveToCurrentWord();
+ }
+}
+
+void ScintillaBase::AutoCompleteCharacterDeleted() {
+ if (currentPos < ac.posStart - ac.startLen) {
+ ac.Cancel();
+ } else if (ac.cancelAtStartPos && (currentPos <= ac.posStart)) {
+ ac.Cancel();
+ } else {
+ AutoCompleteMoveToCurrentWord();
+ }
+}
+
+void ScintillaBase::AutoCompleteCompleted() {
+ int item = ac.lb->GetSelection();
+ char selected[1000];
+ selected[0] = '\0';
+ if (item != -1) {
+ ac.lb->GetValue(item, selected, sizeof(selected));
+ } else {
+ ac.Cancel();
+ return;
+ }
+
+ ac.Show(false);
+
+ listSelected = selected;
+ SCNotification scn = {0};
+ scn.nmhdr.code = listType > 0 ? SCN_USERLISTSELECTION : SCN_AUTOCSELECTION;
+ scn.message = 0;
+ scn.wParam = listType;
+ scn.listType = listType;
+ Position firstPos = ac.posStart - ac.startLen;
+ scn.lParam = firstPos;
+ scn.text = listSelected.c_str();
+ NotifyParent(scn);
+
+ if (!ac.Active())
+ return;
+ ac.Cancel();
+
+ if (listType > 0)
+ return;
+
+ Position endPos = currentPos;
+ if (ac.dropRestOfWord)
+ endPos = pdoc->ExtendWordSelect(endPos, 1, true);
+ if (endPos < firstPos)
+ return;
+ pdoc->BeginUndoAction();
+ if (endPos != firstPos) {
+ pdoc->DeleteChars(firstPos, endPos - firstPos);
+ }
+ SetEmptySelection(ac.posStart);
+ if (item != -1) {
+ SString piece = selected;
+ pdoc->InsertString(firstPos, piece.c_str());
+ SetEmptySelection(firstPos + static_cast<int>(piece.length()));
+ }
+ pdoc->EndUndoAction();
+}
+
+int ScintillaBase::AutoCompleteGetCurrent() {
+ return ac.lb->GetSelection();
+}
+
+void ScintillaBase::CallTipShow(Point pt, const char *defn) {
+ AutoCompleteCancel();
+ pt.y += vs.lineHeight;
+ // 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);
+ }
+ PRectangle rc = ct.CallTipStart(currentPos, pt,
+ defn,
+ vs.styles[ctStyle].fontName,
+ vs.styles[ctStyle].sizeZoomed,
+ CodePage(),
+ vs.styles[ctStyle].characterSet,
+ wMain);
+ // If the call-tip window would be out of the client
+ // space, adjust so it displays above the text.
+ PRectangle rcClient = GetClientRectangle();
+ if (rc.bottom > rcClient.bottom) {
+ int offset = vs.lineHeight + rc.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 = {0};
+ 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 && 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);
+ }
+}
+
+void ScintillaBase::CancelModes() {
+ AutoCompleteCancel();
+ ct.CallTipCancel();
+ Editor::CancelModes();
+}
+
+void ScintillaBase::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) {
+ CancelModes();
+ Editor::ButtonDown(pt, curTime, shift, ctrl, alt);
+}
+
+#ifdef SCI_LEXER
+void ScintillaBase::SetLexer(uptr_t wParam) {
+ lexLanguage = wParam;
+ lexCurrent = LexerModule::Find(lexLanguage);
+ if (!lexCurrent)
+ lexCurrent = LexerModule::Find(SCLEX_NULL);
+}
+
+void ScintillaBase::SetLexerLanguage(const char *languageName) {
+ lexLanguage = SCLEX_CONTAINER;
+ lexCurrent = LexerModule::Find(languageName);
+ if (!lexCurrent)
+ lexCurrent = LexerModule::Find(SCLEX_NULL);
+ if (lexCurrent)
+ lexLanguage = lexCurrent->GetLanguage();
+}
+
+void ScintillaBase::Colourise(int start, int end) {
+ if (!performingStyle) {
+ // Protect against reentrance, which may occur, for example, when
+ // fold points are discovered while performing styling and the folding
+ // code looks for child lines which may trigger styling.
+ performingStyle = true;
+
+ int lengthDoc = pdoc->Length();
+ if (end == -1)
+ end = lengthDoc;
+ int len = end - start;
+
+ PLATFORM_ASSERT(len >= 0);
+ PLATFORM_ASSERT(start + len <= lengthDoc);
+
+ //WindowAccessor styler(wMain.GetID(), props);
+ DocumentAccessor styler(pdoc, props, wMain.GetID());
+
+ int styleStart = 0;
+ if (start > 0)
+ styleStart = styler.StyleAt(start - 1) & pdoc->stylingBitsMask;
+ styler.SetCodePage(pdoc->dbcsCodePage);
+
+ if (lexCurrent && (len > 0)) { // Should always succeed as null lexer should always be available
+ lexCurrent->Lex(start, len, styleStart, keyWordLists, styler);
+ styler.Flush();
+ if (styler.GetPropertyInt("fold")) {
+ lexCurrent->Fold(start, len, styleStart, keyWordLists, styler);
+ styler.Flush();
+ }
+ }
+
+ performingStyle = false;
+ }
+}
+#endif
+
+void ScintillaBase::NotifyStyleToNeeded(int endStyleNeeded) {
+#ifdef SCI_LEXER
+ if (lexLanguage != SCLEX_CONTAINER) {
+ int endStyled = WndProc(SCI_GETENDSTYLED, 0, 0);
+ int lineEndStyled = WndProc(SCI_LINEFROMPOSITION, endStyled, 0);
+ endStyled = WndProc(SCI_POSITIONFROMLINE, lineEndStyled, 0);
+ Colourise(endStyled, endStyleNeeded);
+ return;
+ }
+#endif
+ Editor::NotifyStyleToNeeded(endStyleNeeded);
+}
+
+sptr_t ScintillaBase::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
+ switch (iMessage) {
+ case SCI_AUTOCSHOW:
+ listType = 0;
+ AutoCompleteStart(wParam, reinterpret_cast<const char *>(lParam));
+ break;
+
+ case SCI_AUTOCCANCEL:
+ AutoCompleteCancel();
+ break;
+
+ case SCI_AUTOCACTIVE:
+ return ac.Active();
+
+ case SCI_AUTOCPOSSTART:
+ return ac.posStart;
+
+ case SCI_AUTOCCOMPLETE:
+ AutoCompleteCompleted();
+ break;
+
+ case SCI_AUTOCSETSEPARATOR:
+ ac.SetSeparator(static_cast<char>(wParam));
+ break;
+
+ case SCI_AUTOCGETSEPARATOR:
+ return ac.GetSeparator();
+
+ case SCI_AUTOCSTOPS:
+ ac.SetStopChars(reinterpret_cast<char *>(lParam));
+ break;
+
+ case SCI_AUTOCSELECT:
+ ac.Select(reinterpret_cast<char *>(lParam));
+ break;
+
+ case SCI_AUTOCGETCURRENT:
+ return AutoCompleteGetCurrent();
+
+ case SCI_AUTOCSETCANCELATSTART:
+ ac.cancelAtStartPos = wParam != 0;
+ break;
+
+ case SCI_AUTOCGETCANCELATSTART:
+ return ac.cancelAtStartPos;
+
+ case SCI_AUTOCSETFILLUPS:
+ ac.SetFillUpChars(reinterpret_cast<char *>(lParam));
+ break;
+
+ case SCI_AUTOCSETCHOOSESINGLE:
+ ac.chooseSingle = wParam != 0;
+ break;
+
+ case SCI_AUTOCGETCHOOSESINGLE:
+ return ac.chooseSingle;
+
+ case SCI_AUTOCSETIGNORECASE:
+ ac.ignoreCase = wParam != 0;
+ break;
+
+ case SCI_AUTOCGETIGNORECASE:
+ return ac.ignoreCase;
+
+ case SCI_USERLISTSHOW:
+ listType = wParam;
+ AutoCompleteStart(0, reinterpret_cast<const char *>(lParam));
+ break;
+
+ case SCI_AUTOCSETAUTOHIDE:
+ ac.autoHide = wParam != 0;
+ break;
+
+ case SCI_AUTOCGETAUTOHIDE:
+ return ac.autoHide;
+
+ case SCI_AUTOCSETDROPRESTOFWORD:
+ ac.dropRestOfWord = wParam != 0;
+ break;
+
+ case SCI_AUTOCGETDROPRESTOFWORD:
+ return ac.dropRestOfWord;
+
+ case SCI_AUTOCSETMAXHEIGHT:
+ ac.lb->SetVisibleRows(wParam);
+ break;
+
+ case SCI_AUTOCGETMAXHEIGHT:
+ return ac.lb->GetVisibleRows();
+
+ case SCI_AUTOCSETMAXWIDTH:
+ maxListWidth = wParam;
+ break;
+
+ case SCI_AUTOCGETMAXWIDTH:
+ return maxListWidth;
+
+ case SCI_REGISTERIMAGE:
+ ac.lb->RegisterImage(wParam, reinterpret_cast<const char *>(lParam));
+ break;
+
+ case SCI_CLEARREGISTEREDIMAGES:
+ ac.lb->ClearRegisteredImages();
+ break;
+
+ case SCI_AUTOCSETTYPESEPARATOR:
+ ac.SetTypesep(static_cast<char>(wParam));
+ break;
+
+ case SCI_AUTOCGETTYPESEPARATOR:
+ return ac.GetTypesep();
+
+ case SCI_CALLTIPSHOW:
+ CallTipShow(LocationFromPosition(wParam),
+ reinterpret_cast<const char *>(lParam));
+ break;
+
+ case SCI_CALLTIPCANCEL:
+ ct.CallTipCancel();
+ break;
+
+ case SCI_CALLTIPACTIVE:
+ return ct.inCallTipMode;
+
+ case SCI_CALLTIPPOSSTART:
+ return ct.posStartCallTip;
+
+ case SCI_CALLTIPSETHLT:
+ ct.SetHighlight(wParam, lParam);
+ break;
+
+ case SCI_CALLTIPSETBACK:
+ ct.colourBG = ColourDesired(wParam);
+ vs.styles[STYLE_CALLTIP].fore = ct.colourBG;
+ InvalidateStyleRedraw();
+ break;
+
+ case SCI_CALLTIPSETFORE:
+ ct.colourUnSel = ColourDesired(wParam);
+ vs.styles[STYLE_CALLTIP].fore = ct.colourUnSel;
+ InvalidateStyleRedraw();
+ break;
+
+ case SCI_CALLTIPSETFOREHLT:
+ ct.colourSel = ColourDesired(wParam);
+ InvalidateStyleRedraw();
+ break;
+
+ case SCI_CALLTIPUSESTYLE:
+ ct.SetTabSize((int)wParam);
+ InvalidateStyleRedraw();
+ break;
+
+ case SCI_USEPOPUP:
+ displayPopupMenu = wParam != 0;
+ break;
+
+#ifdef SCI_LEXER
+ case SCI_SETLEXER:
+ SetLexer(wParam);
+ lexLanguage = wParam;
+ break;
+
+ case SCI_GETLEXER:
+ return lexLanguage;
+
+ case SCI_COLOURISE:
+ if (lexLanguage == SCLEX_CONTAINER) {
+ pdoc->ModifiedAt(wParam);
+ NotifyStyleToNeeded((lParam == -1) ? pdoc->Length() : lParam);
+ } else {
+ Colourise(wParam, lParam);
+ }
+ Redraw();
+ break;
+
+ case SCI_SETPROPERTY:
+ props.Set(reinterpret_cast<const char *>(wParam),
+ reinterpret_cast<const char *>(lParam));
+ break;
+
+ case SCI_GETPROPERTY: {
+ SString val = props.Get(reinterpret_cast<const char *>(wParam));
+ const int n = val.length();
+ if (lParam != 0) {
+ char *ptr = reinterpret_cast<char *>(lParam);
+ memcpy(ptr, val.c_str(), n);
+ ptr[n] = '\0'; // terminate
+ }
+ return n; // Not including NUL
+ }
+
+ case SCI_GETPROPERTYEXPANDED: {
+ SString val = props.GetExpanded(reinterpret_cast<const char *>(wParam));
+ const int n = val.length();
+ if (lParam != 0) {
+ char *ptr = reinterpret_cast<char *>(lParam);
+ memcpy(ptr, val.c_str(), n);
+ ptr[n] = '\0'; // terminate
+ }
+ return n; // Not including NUL
+ }
+
+ case SCI_GETPROPERTYINT:
+ return props.GetInt(reinterpret_cast<const char *>(wParam), lParam);
+
+ case SCI_SETKEYWORDS:
+ if (wParam < numWordLists) {
+ keyWordLists[wParam]->Clear();
+ keyWordLists[wParam]->Set(reinterpret_cast<const char *>(lParam));
+ }
+ break;
+
+ case SCI_SETLEXERLANGUAGE:
+ SetLexerLanguage(reinterpret_cast<const char *>(lParam));
+ break;
+
+ case SCI_GETSTYLEBITSNEEDED:
+ return lexCurrent ? lexCurrent->GetStyleBitsNeeded() : 5;
+#endif
+
+ default:
+ return Editor::WndProc(iMessage, wParam, lParam);
+ }
+ return 0l;
+}