xref: /MusicPlayer2/scintilla/src/ScintillaBase.cxx (revision 443d2d2511be730d1b1dd3181942b7fa6539aa1a)
1 // Scintilla source code edit control
2 /** @file ScintillaBase.cxx
3  ** An enhanced subclass of Editor with calltips, autocomplete and context menu.
4  **/
5 // Copyright 1998-2003 by Neil Hodgson <[email protected]>
6 // The License.txt file describes the conditions under which this software may be distributed.
7 
8 #include <cstddef>
9 #include <cstdlib>
10 #include <cassert>
11 #include <cstring>
12 
13 #include <stdexcept>
14 #include <string>
15 #include <string_view>
16 #include <vector>
17 #include <map>
18 #include <algorithm>
19 #include <memory>
20 
21 #include "Platform.h"
22 
23 #include "ILoader.h"
24 #include "ILexer.h"
25 #include "Scintilla.h"
26 
27 #include "SciLexer.h"
28 
29 #include "PropSetSimple.h"
30 #include "CharacterCategory.h"
31 
32 #include "LexerModule.h"
33 #include "Catalogue.h"
34 
35 #include "Position.h"
36 #include "UniqueString.h"
37 #include "SplitVector.h"
38 #include "Partitioning.h"
39 #include "RunStyles.h"
40 #include "ContractionState.h"
41 #include "CellBuffer.h"
42 #include "CallTip.h"
43 #include "KeyMap.h"
44 #include "Indicator.h"
45 #include "LineMarker.h"
46 #include "Style.h"
47 #include "ViewStyle.h"
48 #include "CharClassify.h"
49 #include "Decoration.h"
50 #include "CaseFolder.h"
51 #include "Document.h"
52 #include "Selection.h"
53 #include "PositionCache.h"
54 #include "EditModel.h"
55 #include "MarginView.h"
56 #include "EditView.h"
57 #include "Editor.h"
58 #include "AutoComplete.h"
59 #include "ScintillaBase.h"
60 
61 #include "ExternalLexer.h"
62 
63 #undef max
64 #undef min
65 
66 using namespace Scintilla;
67 
68 ScintillaBase::ScintillaBase() {
69 	displayPopupMenu = SC_POPUP_ALL;
70 	listType = 0;
71 	maxListWidth = 0;
72 	multiAutoCMode = SC_MULTIAUTOC_ONCE;
73 #ifdef SCI_LEXER
74 	Scintilla_LinkLexers();
75 #endif
76 }
77 
78 ScintillaBase::~ScintillaBase() {
79 }
80 
81 void ScintillaBase::Finalise() {
82 	Editor::Finalise();
83 	popup.Destroy();
84 }
85 
86 void ScintillaBase::AddCharUTF(const char *s, unsigned int len, bool /*treatAsDBCS*/) {
87 	InsertCharacter(std::string_view(s, len), CharacterSource::directInput);
88 }
89 
90 void ScintillaBase::InsertCharacter(std::string_view sv, CharacterSource charSource) {
91 	const bool isFillUp = ac.Active() && ac.IsFillUpChar(sv[0]);
92 	if (!isFillUp) {
93 		Editor::InsertCharacter(sv, charSource);
94 	}
95 	if (ac.Active()) {
96 		AutoCompleteCharacterAdded(sv[0]);
97 		// For fill ups add the character after the autocompletion has
98 		// triggered so containers see the key so can display a calltip.
99 		if (isFillUp) {
100 			Editor::InsertCharacter(sv, charSource);
101 		}
102 	}
103 }
104 
105 void ScintillaBase::Command(int cmdId) {
106 
107 	switch (cmdId) {
108 
109 	case idAutoComplete:  	// Nothing to do
110 
111 		break;
112 
113 	case idCallTip:  	// Nothing to do
114 
115 		break;
116 
117 	case idcmdUndo:
118 		WndProc(SCI_UNDO, 0, 0);
119 		break;
120 
121 	case idcmdRedo:
122 		WndProc(SCI_REDO, 0, 0);
123 		break;
124 
125 	case idcmdCut:
126 		WndProc(SCI_CUT, 0, 0);
127 		break;
128 
129 	case idcmdCopy:
130 		WndProc(SCI_COPY, 0, 0);
131 		break;
132 
133 	case idcmdPaste:
134 		WndProc(SCI_PASTE, 0, 0);
135 		break;
136 
137 	case idcmdDelete:
138 		WndProc(SCI_CLEAR, 0, 0);
139 		break;
140 
141 	case idcmdSelectAll:
142 		WndProc(SCI_SELECTALL, 0, 0);
143 		break;
144 	}
145 }
146 
147 int ScintillaBase::KeyCommand(unsigned int iMessage) {
148 	// Most key commands cancel autocompletion mode
149 	if (ac.Active()) {
150 		switch (iMessage) {
151 			// Except for these
152 		case SCI_LINEDOWN:
153 			AutoCompleteMove(1);
154 			return 0;
155 		case SCI_LINEUP:
156 			AutoCompleteMove(-1);
157 			return 0;
158 		case SCI_PAGEDOWN:
159 			AutoCompleteMove(ac.lb->GetVisibleRows());
160 			return 0;
161 		case SCI_PAGEUP:
162 			AutoCompleteMove(-ac.lb->GetVisibleRows());
163 			return 0;
164 		case SCI_VCHOME:
165 			AutoCompleteMove(-5000);
166 			return 0;
167 		case SCI_LINEEND:
168 			AutoCompleteMove(5000);
169 			return 0;
170 		case SCI_DELETEBACK:
171 			DelCharBack(true);
172 			AutoCompleteCharacterDeleted();
173 			EnsureCaretVisible();
174 			return 0;
175 		case SCI_DELETEBACKNOTLINE:
176 			DelCharBack(false);
177 			AutoCompleteCharacterDeleted();
178 			EnsureCaretVisible();
179 			return 0;
180 		case SCI_TAB:
181 			AutoCompleteCompleted(0, SC_AC_TAB);
182 			return 0;
183 		case SCI_NEWLINE:
184 			AutoCompleteCompleted(0, SC_AC_NEWLINE);
185 			return 0;
186 
187 		default:
188 			AutoCompleteCancel();
189 		}
190 	}
191 
192 	if (ct.inCallTipMode) {
193 		if (
194 		    (iMessage != SCI_CHARLEFT) &&
195 		    (iMessage != SCI_CHARLEFTEXTEND) &&
196 		    (iMessage != SCI_CHARRIGHT) &&
197 		    (iMessage != SCI_CHARRIGHTEXTEND) &&
198 		    (iMessage != SCI_EDITTOGGLEOVERTYPE) &&
199 		    (iMessage != SCI_DELETEBACK) &&
200 		    (iMessage != SCI_DELETEBACKNOTLINE)
201 		) {
202 			ct.CallTipCancel();
203 		}
204 		if ((iMessage == SCI_DELETEBACK) || (iMessage == SCI_DELETEBACKNOTLINE)) {
205 			if (sel.MainCaret() <= ct.posStartCallTip) {
206 				ct.CallTipCancel();
207 			}
208 		}
209 	}
210 	return Editor::KeyCommand(iMessage);
211 }
212 
213 void ScintillaBase::ListNotify(ListBoxEvent *plbe) {
214 	switch (plbe->event) {
215 	case ListBoxEvent::EventType::selectionChange:
216 		AutoCompleteSelection();
217 		break;
218 	case ListBoxEvent::EventType::doubleClick:
219 		AutoCompleteCompleted(0, SC_AC_DOUBLECLICK);
220 		break;
221 	}
222 }
223 
224 void ScintillaBase::AutoCompleteInsert(Sci::Position startPos, Sci::Position removeLen, const char *text, Sci::Position textLen) {
225 	UndoGroup ug(pdoc);
226 	if (multiAutoCMode == SC_MULTIAUTOC_ONCE) {
227 		pdoc->DeleteChars(startPos, removeLen);
228 		const Sci::Position lengthInserted = pdoc->InsertString(startPos, text, textLen);
229 		SetEmptySelection(startPos + lengthInserted);
230 	} else {
231 		// SC_MULTIAUTOC_EACH
232 		for (size_t r=0; r<sel.Count(); r++) {
233 			if (!RangeContainsProtected(sel.Range(r).Start().Position(),
234 				sel.Range(r).End().Position())) {
235 				Sci::Position positionInsert = sel.Range(r).Start().Position();
236 				positionInsert = RealizeVirtualSpace(positionInsert, sel.Range(r).caret.VirtualSpace());
237 				if (positionInsert - removeLen >= 0) {
238 					positionInsert -= removeLen;
239 					pdoc->DeleteChars(positionInsert, removeLen);
240 				}
241 				const Sci::Position lengthInserted = pdoc->InsertString(positionInsert, text, textLen);
242 				if (lengthInserted > 0) {
243 					sel.Range(r).caret.SetPosition(positionInsert + lengthInserted);
244 					sel.Range(r).anchor.SetPosition(positionInsert + lengthInserted);
245 				}
246 				sel.Range(r).ClearVirtualSpace();
247 			}
248 		}
249 	}
250 }
251 
252 void ScintillaBase::AutoCompleteStart(Sci::Position lenEntered, const char *list) {
253 	//Platform::DebugPrintf("AutoComplete %s\n", list);
254 	ct.CallTipCancel();
255 
256 	if (ac.chooseSingle && (listType == 0)) {
257 		if (list && !strchr(list, ac.GetSeparator())) {
258 			const char *typeSep = strchr(list, ac.GetTypesep());
259 			const Sci::Position lenInsert = typeSep ?
260 				(typeSep-list) : strlen(list);
261 			if (ac.ignoreCase) {
262 				// May need to convert the case before invocation, so remove lenEntered characters
263 				AutoCompleteInsert(sel.MainCaret() - lenEntered, lenEntered, list, lenInsert);
264 			} else {
265 				AutoCompleteInsert(sel.MainCaret(), 0, list + lenEntered, lenInsert - lenEntered);
266 			}
267 			ac.Cancel();
268 			return;
269 		}
270 	}
271 	ac.Start(wMain, idAutoComplete, sel.MainCaret(), PointMainCaret(),
272 				lenEntered, vs.lineHeight, IsUnicodeMode(), technology);
273 
274 	const PRectangle rcClient = GetClientRectangle();
275 	Point pt = LocationFromPosition(sel.MainCaret() - lenEntered);
276 	PRectangle rcPopupBounds = wMain.GetMonitorRect(pt);
277 	if (rcPopupBounds.Height() == 0)
278 		rcPopupBounds = rcClient;
279 
280 	int heightLB = ac.heightLBDefault;
281 	int widthLB = ac.widthLBDefault;
282 	if (pt.x >= rcClient.right - widthLB) {
283 		HorizontalScrollTo(static_cast<int>(xOffset + pt.x - rcClient.right + widthLB));
284 		Redraw();
285 		pt = PointMainCaret();
286 	}
287 	if (wMargin.Created()) {
288 		pt = pt + GetVisibleOriginInMain();
289 	}
290 	PRectangle rcac;
291 	rcac.left = pt.x - ac.lb->CaretFromEdge();
292 	if (pt.y >= rcPopupBounds.bottom - heightLB &&  // Won't fit below.
293 	        pt.y >= (rcPopupBounds.bottom + rcPopupBounds.top) / 2) { // and there is more room above.
294 		rcac.top = pt.y - heightLB;
295 		if (rcac.top < rcPopupBounds.top) {
296 			heightLB -= static_cast<int>(rcPopupBounds.top - rcac.top);
297 			rcac.top = rcPopupBounds.top;
298 		}
299 	} else {
300 		rcac.top = pt.y + vs.lineHeight;
301 	}
302 	rcac.right = rcac.left + widthLB;
303 	rcac.bottom = static_cast<XYPOSITION>(std::min(static_cast<int>(rcac.top) + heightLB, static_cast<int>(rcPopupBounds.bottom)));
304 	ac.lb->SetPositionRelative(rcac, &wMain);
305 	ac.lb->SetFont(vs.styles[STYLE_DEFAULT].font);
306 	const unsigned int aveCharWidth = static_cast<unsigned int>(vs.styles[STYLE_DEFAULT].aveCharWidth);
307 	ac.lb->SetAverageCharWidth(aveCharWidth);
308 	ac.lb->SetDelegate(this);
309 
310 	ac.SetList(list ? list : "");
311 
312 	// Fiddle the position of the list so it is right next to the target and wide enough for all its strings
313 	PRectangle rcList = ac.lb->GetDesiredRect();
314 	const int heightAlloced = static_cast<int>(rcList.bottom - rcList.top);
315 	widthLB = std::max(widthLB, static_cast<int>(rcList.right - rcList.left));
316 	if (maxListWidth != 0)
317 		widthLB = std::min(widthLB, static_cast<int>(aveCharWidth)*maxListWidth);
318 	// Make an allowance for large strings in list
319 	rcList.left = pt.x - ac.lb->CaretFromEdge();
320 	rcList.right = rcList.left + widthLB;
321 	if (((pt.y + vs.lineHeight) >= (rcPopupBounds.bottom - heightAlloced)) &&  // Won't fit below.
322 	        ((pt.y + vs.lineHeight / 2) >= (rcPopupBounds.bottom + rcPopupBounds.top) / 2)) { // and there is more room above.
323 		rcList.top = pt.y - heightAlloced;
324 	} else {
325 		rcList.top = pt.y + vs.lineHeight;
326 	}
327 	rcList.bottom = rcList.top + heightAlloced;
328 	ac.lb->SetPositionRelative(rcList, &wMain);
329 	ac.Show(true);
330 	if (lenEntered != 0) {
331 		AutoCompleteMoveToCurrentWord();
332 	}
333 }
334 
335 void ScintillaBase::AutoCompleteCancel() {
336 	if (ac.Active()) {
337 		SCNotification scn = {};
338 		scn.nmhdr.code = SCN_AUTOCCANCELLED;
339 		scn.wParam = 0;
340 		scn.listType = 0;
341 		NotifyParent(scn);
342 	}
343 	ac.Cancel();
344 }
345 
346 void ScintillaBase::AutoCompleteMove(int delta) {
347 	ac.Move(delta);
348 }
349 
350 void ScintillaBase::AutoCompleteMoveToCurrentWord() {
351 	std::string wordCurrent = RangeText(ac.posStart - ac.startLen, sel.MainCaret());
352 	ac.Select(wordCurrent.c_str());
353 }
354 
355 void ScintillaBase::AutoCompleteSelection() {
356 	const int item = ac.GetSelection();
357 	std::string selected;
358 	if (item != -1) {
359 		selected = ac.GetValue(item);
360 	}
361 
362 	SCNotification scn = {};
363 	scn.nmhdr.code = SCN_AUTOCSELECTIONCHANGE;
364 	scn.message = 0;
365 	scn.wParam = listType;
366 	scn.listType = listType;
367 	const Sci::Position firstPos = ac.posStart - ac.startLen;
368 	scn.position = firstPos;
369 	scn.lParam = firstPos;
370 	scn.text = selected.c_str();
371 	NotifyParent(scn);
372 }
373 
374 void ScintillaBase::AutoCompleteCharacterAdded(char ch) {
375 	if (ac.IsFillUpChar(ch)) {
376 		AutoCompleteCompleted(ch, SC_AC_FILLUP);
377 	} else if (ac.IsStopChar(ch)) {
378 		AutoCompleteCancel();
379 	} else {
380 		AutoCompleteMoveToCurrentWord();
381 	}
382 }
383 
384 void ScintillaBase::AutoCompleteCharacterDeleted() {
385 	if (sel.MainCaret() < ac.posStart - ac.startLen) {
386 		AutoCompleteCancel();
387 	} else if (ac.cancelAtStartPos && (sel.MainCaret() <= ac.posStart)) {
388 		AutoCompleteCancel();
389 	} else {
390 		AutoCompleteMoveToCurrentWord();
391 	}
392 	SCNotification scn = {};
393 	scn.nmhdr.code = SCN_AUTOCCHARDELETED;
394 	scn.wParam = 0;
395 	scn.listType = 0;
396 	NotifyParent(scn);
397 }
398 
399 void ScintillaBase::AutoCompleteCompleted(char ch, unsigned int completionMethod) {
400 	const int item = ac.GetSelection();
401 	if (item == -1) {
402 		AutoCompleteCancel();
403 		return;
404 	}
405 	const std::string selected = ac.GetValue(item);
406 
407 	ac.Show(false);
408 
409 	SCNotification scn = {};
410 	scn.nmhdr.code = listType > 0 ? SCN_USERLISTSELECTION : SCN_AUTOCSELECTION;
411 	scn.message = 0;
412 	scn.ch = ch;
413 	scn.listCompletionMethod = completionMethod;
414 	scn.wParam = listType;
415 	scn.listType = listType;
416 	const Sci::Position firstPos = ac.posStart - ac.startLen;
417 	scn.position = firstPos;
418 	scn.lParam = firstPos;
419 	scn.text = selected.c_str();
420 	NotifyParent(scn);
421 
422 	if (!ac.Active())
423 		return;
424 	ac.Cancel();
425 
426 	if (listType > 0)
427 		return;
428 
429 	Sci::Position endPos = sel.MainCaret();
430 	if (ac.dropRestOfWord)
431 		endPos = pdoc->ExtendWordSelect(endPos, 1, true);
432 	if (endPos < firstPos)
433 		return;
434 	AutoCompleteInsert(firstPos, endPos - firstPos, selected.c_str(), selected.length());
435 	SetLastXChosen();
436 
437 	scn.nmhdr.code = SCN_AUTOCCOMPLETED;
438 	NotifyParent(scn);
439 
440 }
441 
442 int ScintillaBase::AutoCompleteGetCurrent() const {
443 	if (!ac.Active())
444 		return -1;
445 	return ac.GetSelection();
446 }
447 
448 int ScintillaBase::AutoCompleteGetCurrentText(char *buffer) const {
449 	if (ac.Active()) {
450 		const int item = ac.GetSelection();
451 		if (item != -1) {
452 			const std::string selected = ac.GetValue(item);
453 			if (buffer)
454 				memcpy(buffer, selected.c_str(), selected.length()+1);
455 			return static_cast<int>(selected.length());
456 		}
457 	}
458 	if (buffer)
459 		*buffer = '\0';
460 	return 0;
461 }
462 
463 void ScintillaBase::CallTipShow(Point pt, const char *defn) {
464 	ac.Cancel();
465 	// If container knows about STYLE_CALLTIP then use it in place of the
466 	// STYLE_DEFAULT for the face name, size and character set. Also use it
467 	// for the foreground and background colour.
468 	const int ctStyle = ct.UseStyleCallTip() ? STYLE_CALLTIP : STYLE_DEFAULT;
469 	if (ct.UseStyleCallTip()) {
470 		ct.SetForeBack(vs.styles[STYLE_CALLTIP].fore, vs.styles[STYLE_CALLTIP].back);
471 	}
472 	if (wMargin.Created()) {
473 		pt = pt + GetVisibleOriginInMain();
474 	}
475 	PRectangle rc = ct.CallTipStart(sel.MainCaret(), pt,
476 		vs.lineHeight,
477 		defn,
478 		vs.styles[ctStyle].fontName,
479 		vs.styles[ctStyle].sizeZoomed,
480 		CodePage(),
481 		vs.styles[ctStyle].characterSet,
482 		vs.technology,
483 		wMain);
484 	// If the call-tip window would be out of the client
485 	// space
486 	const PRectangle rcClient = GetClientRectangle();
487 	const int offset = vs.lineHeight + static_cast<int>(rc.Height());
488 	// adjust so it displays above the text.
489 	if (rc.bottom > rcClient.bottom && rc.Height() < rcClient.Height()) {
490 		rc.top -= offset;
491 		rc.bottom -= offset;
492 	}
493 	// adjust so it displays below the text.
494 	if (rc.top < rcClient.top && rc.Height() < rcClient.Height()) {
495 		rc.top += offset;
496 		rc.bottom += offset;
497 	}
498 	// Now display the window.
499 	CreateCallTipWindow(rc);
500 	ct.wCallTip.SetPositionRelative(rc, &wMain);
501 	ct.wCallTip.Show();
502 }
503 
504 void ScintillaBase::CallTipClick() {
505 	SCNotification scn = {};
506 	scn.nmhdr.code = SCN_CALLTIPCLICK;
507 	scn.position = ct.clickPlace;
508 	NotifyParent(scn);
509 }
510 
511 bool ScintillaBase::ShouldDisplayPopup(Point ptInWindowCoordinates) const {
512 	return (displayPopupMenu == SC_POPUP_ALL ||
513 		(displayPopupMenu == SC_POPUP_TEXT && !PointInSelMargin(ptInWindowCoordinates)));
514 }
515 
516 void ScintillaBase::ContextMenu(Point pt) {
517     auto LoadText = [this](const std::wstring& key) -> std::wstring {
518         if (menuStringTable != nullptr) {
519             auto it = menuStringTable->find(key);
520             if (it != menuStringTable->end()) {
521                 return it->second;
522             }
523         }
524         return L"";
525     };  // 此方法依赖menuStringTable,不适合作为全局函数
526 	if (displayPopupMenu) {
527 		const bool writable = !WndProc(SCI_GETREADONLY, 0, 0);
528 		popup.CreatePopUp();
529         std::wstring temp;
530         temp = LoadText(L"TXT_SCI_UNDO");
531         AddToPopUp(((temp.empty() ? L"Undo" : temp) + L"\tCtrl+Z").c_str(), idcmdUndo, writable&& pdoc->CanUndo());
532         temp = LoadText(L"TXT_SCI_REDO");
533         AddToPopUp(((temp.empty() ? L"Redo" : temp) + L"\tCtrl+Y").c_str(), idcmdRedo, writable && pdoc->CanRedo());
534         AddToPopUp(L"");
535         temp = LoadText(L"TXT_SCI_CUT");
536         AddToPopUp(((temp.empty() ? L"Cut" : temp) + L"\tCtrl+X").c_str(), idcmdCut, writable && !sel.Empty());
537         temp = LoadText(L"TXT_SCI_COPY");
538         AddToPopUp(((temp.empty() ? L"Copy" : temp) + L"\tCtrl+C").c_str(), idcmdCopy, !sel.Empty());
539         temp = LoadText(L"TXT_SCI_PASTE");
540         AddToPopUp(((temp.empty() ? L"Paste" : temp) + L"\tCtrl+V").c_str(), idcmdPaste, writable && WndProc(SCI_CANPASTE, 0, 0));
541         temp = LoadText(L"TXT_SCI_DELETE");
542         AddToPopUp((temp.empty() ? L"Clear" : temp).c_str(), idcmdDelete, writable && !sel.Empty());
543         AddToPopUp(L"");
544         temp = LoadText(L"TXT_SCI_SELECT_ALL");
545         AddToPopUp(((temp.empty() ? L"Select All" : temp) + L"\tCtrl+A").c_str(), idcmdSelectAll);
546         popup.Show(pt, wMain);
547 	}
548 }
549 
550 void ScintillaBase::CancelModes() {
551 	AutoCompleteCancel();
552 	ct.CallTipCancel();
553 	Editor::CancelModes();
554 }
555 
556 void ScintillaBase::ButtonDownWithModifiers(Point pt, unsigned int curTime, int modifiers) {
557 	CancelModes();
558 	Editor::ButtonDownWithModifiers(pt, curTime, modifiers);
559 }
560 
561 void ScintillaBase::RightButtonDownWithModifiers(Point pt, unsigned int curTime, int modifiers) {
562 	CancelModes();
563 	Editor::RightButtonDownWithModifiers(pt, curTime, modifiers);
564 }
565 
566 namespace Scintilla {
567 
568 class LexState : public LexInterface {
569 	const LexerModule *lexCurrent;
570 	void SetLexerModule(const LexerModule *lex);
571 	PropSetSimple props;
572 	int interfaceVersion;
573 public:
574 	int lexLanguage;
575 
576 	explicit LexState(Document *pdoc_);
577 	void SetInstance(ILexer5 *instance_);
578 	// Deleted so LexState objects can not be copied.
579 	LexState(const LexState &) = delete;
580 	LexState(LexState &&) = delete;
581 	LexState &operator=(const LexState &) = delete;
582 	LexState &operator=(LexState &&) = delete;
583 	~LexState() override;
584 	void SetLexer(uptr_t wParam);
585 	void SetLexerLanguage(const char *languageName);
586 
587 	const char *DescribeWordListSets();
588 	void SetWordList(int n, const char *wl);
589 	int GetIdentifier() const;
590 	const char *GetName() const;
591 	void *PrivateCall(int operation, void *pointer);
592 	const char *PropertyNames();
593 	int PropertyType(const char *name);
594 	const char *DescribeProperty(const char *name);
595 	void PropSet(const char *key, const char *val);
596 	const char *PropGet(const char *key) const;
597 	int PropGetInt(const char *key, int defaultValue=0) const;
598 	size_t PropGetExpanded(const char *key, char *result) const;
599 
600 	int LineEndTypesSupported() override;
601 	int AllocateSubStyles(int styleBase, int numberStyles);
602 	int SubStylesStart(int styleBase);
603 	int SubStylesLength(int styleBase);
604 	int StyleFromSubStyle(int subStyle);
605 	int PrimaryStyleFromStyle(int style);
606 	void FreeSubStyles();
607 	void SetIdentifiers(int style, const char *identifiers);
608 	int DistanceToSecondaryStyles();
609 	const char *GetSubStyleBases();
610 	int NamedStyles();
611 	const char *NameOfStyle(int style);
612 	const char *TagsOfStyle(int style);
613 	const char *DescriptionOfStyle(int style);
614 };
615 
616 }
617 
618 LexState::LexState(Document *pdoc_) : LexInterface(pdoc_) {
619 	lexCurrent = nullptr;
620 	performingStyle = false;
621 	interfaceVersion = lvRelease4;
622 	lexLanguage = SCLEX_CONTAINER;
623 }
624 
625 LexState::~LexState() {
626 	if (instance) {
627 		instance->Release();
628 		instance = nullptr;
629 	}
630 }
631 
632 void LexState::SetInstance(ILexer5 *instance_) {
633 	if (instance) {
634 		instance->Release();
635 		instance = nullptr;
636 	}
637 	instance = instance_;
638 	pdoc->LexerChanged();
639 }
640 
641 LexState *ScintillaBase::DocumentLexState() {
642 	if (!pdoc->GetLexInterface()) {
643 		pdoc->SetLexInterface(std::make_unique<LexState>(pdoc));
644 	}
645 	return dynamic_cast<LexState *>(pdoc->GetLexInterface());
646 }
647 
648 void LexState::SetLexerModule(const LexerModule *lex) {
649 	if (lex != lexCurrent) {
650 		if (instance) {
651 			instance->Release();
652 			instance = nullptr;
653 		}
654 		interfaceVersion = lvRelease4;
655 		lexCurrent = lex;
656 		if (lexCurrent) {
657 			instance = lexCurrent->Create();
658 			interfaceVersion = instance->Version();
659 		}
660 		pdoc->LexerChanged();
661 	}
662 }
663 
664 void LexState::SetLexer(uptr_t wParam) {
665 	lexLanguage = static_cast<int>(wParam);
666 	if (lexLanguage == SCLEX_CONTAINER) {
667 		SetLexerModule(nullptr);
668 	} else {
669 		const LexerModule *lex = Catalogue::Find(lexLanguage);
670 		if (!lex)
671 			lex = Catalogue::Find(SCLEX_NULL);
672 		SetLexerModule(lex);
673 	}
674 }
675 
676 void LexState::SetLexerLanguage(const char *languageName) {
677 	const LexerModule *lex = Catalogue::Find(languageName);
678 	if (!lex)
679 		lex = Catalogue::Find(SCLEX_NULL);
680 	if (lex)
681 		lexLanguage = lex->GetLanguage();
682 	SetLexerModule(lex);
683 }
684 
685 const char *LexState::DescribeWordListSets() {
686 	if (instance) {
687 		return instance->DescribeWordListSets();
688 	} else {
689 		return nullptr;
690 	}
691 }
692 
693 void LexState::SetWordList(int n, const char *wl) {
694 	if (instance) {
695 		const Sci_Position firstModification = instance->WordListSet(n, wl);
696 		if (firstModification >= 0) {
697 			pdoc->ModifiedAt(firstModification);
698 		}
699 	}
700 }
701 
702 int LexState::GetIdentifier() const {
703 	if (lexCurrent) {
704 		return lexCurrent->GetLanguage();
705 	}
706 	if (instance) {
707 		if (instance->Version() >= lvRelease5) {
708 			return instance->GetIdentifier();
709 		}
710 	}
711 	return SCLEX_CONTAINER;
712 }
713 
714 const char *LexState::GetName() const {
715 	if (lexCurrent) {
716 		return lexCurrent->languageName;
717 	}
718 	if (instance) {
719 		if (instance->Version() >= lvRelease5) {
720 			return instance->GetName();
721 		}
722 	}
723 	return "";
724 }
725 
726 void *LexState::PrivateCall(int operation, void *pointer) {
727 	if (pdoc && instance) {
728 		return instance->PrivateCall(operation, pointer);
729 	} else {
730 		return nullptr;
731 	}
732 }
733 
734 const char *LexState::PropertyNames() {
735 	if (instance) {
736 		return instance->PropertyNames();
737 	} else {
738 		return nullptr;
739 	}
740 }
741 
742 int LexState::PropertyType(const char *name) {
743 	if (instance) {
744 		return instance->PropertyType(name);
745 	} else {
746 		return SC_TYPE_BOOLEAN;
747 	}
748 }
749 
750 const char *LexState::DescribeProperty(const char *name) {
751 	if (instance) {
752 		return instance->DescribeProperty(name);
753 	} else {
754 		return nullptr;
755 	}
756 }
757 
758 void LexState::PropSet(const char *key, const char *val) {
759 	props.Set(key, val, strlen(key), strlen(val));
760 	if (instance) {
761 		const Sci_Position firstModification = instance->PropertySet(key, val);
762 		if (firstModification >= 0) {
763 			pdoc->ModifiedAt(firstModification);
764 		}
765 	}
766 }
767 
768 const char *LexState::PropGet(const char *key) const {
769 	return props.Get(key);
770 }
771 
772 int LexState::PropGetInt(const char *key, int defaultValue) const {
773 	return props.GetInt(key, defaultValue);
774 }
775 
776 size_t LexState::PropGetExpanded(const char *key, char *result) const {
777 	return props.GetExpanded(key, result);
778 }
779 
780 int LexState::LineEndTypesSupported() {
781 	if (instance) {
782 		return instance->LineEndTypesSupported();
783 	}
784 	return 0;
785 }
786 
787 int LexState::AllocateSubStyles(int styleBase, int numberStyles) {
788 	if (instance) {
789 		return instance->AllocateSubStyles(styleBase, numberStyles);
790 	}
791 	return -1;
792 }
793 
794 int LexState::SubStylesStart(int styleBase) {
795 	if (instance) {
796 		return instance->SubStylesStart(styleBase);
797 	}
798 	return -1;
799 }
800 
801 int LexState::SubStylesLength(int styleBase) {
802 	if (instance) {
803 		return instance->SubStylesLength(styleBase);
804 	}
805 	return 0;
806 }
807 
808 int LexState::StyleFromSubStyle(int subStyle) {
809 	if (instance) {
810 		return instance->StyleFromSubStyle(subStyle);
811 	}
812 	return 0;
813 }
814 
815 int LexState::PrimaryStyleFromStyle(int style) {
816 	if (instance) {
817 		return instance->PrimaryStyleFromStyle(style);
818 	}
819 	return 0;
820 }
821 
822 void LexState::FreeSubStyles() {
823 	if (instance) {
824 		instance->FreeSubStyles();
825 	}
826 }
827 
828 void LexState::SetIdentifiers(int style, const char *identifiers) {
829 	if (instance) {
830 		instance->SetIdentifiers(style, identifiers);
831 		pdoc->ModifiedAt(0);
832 	}
833 }
834 
835 int LexState::DistanceToSecondaryStyles() {
836 	if (instance) {
837 		return instance->DistanceToSecondaryStyles();
838 	}
839 	return 0;
840 }
841 
842 const char *LexState::GetSubStyleBases() {
843 	if (instance) {
844 		return instance->GetSubStyleBases();
845 	}
846 	return "";
847 }
848 
849 int LexState::NamedStyles() {
850 	if (instance) {
851 		return instance->NamedStyles();
852 	} else {
853 		return -1;
854 	}
855 }
856 
857 const char *LexState::NameOfStyle(int style) {
858 	if (instance) {
859 		return instance->NameOfStyle(style);
860 	} else {
861 		return nullptr;
862 	}
863 }
864 
865 const char *LexState::TagsOfStyle(int style) {
866 	if (instance) {
867 		return instance->TagsOfStyle(style);
868 	} else {
869 		return nullptr;
870 	}
871 }
872 
873 const char *LexState::DescriptionOfStyle(int style) {
874 	if (instance) {
875 		return instance->DescriptionOfStyle(style);
876 	} else {
877 		return nullptr;
878 	}
879 }
880 
881 void ScintillaBase::NotifyStyleToNeeded(Sci::Position endStyleNeeded) {
882 	if (DocumentLexState()->GetIdentifier() != SCLEX_CONTAINER) {
883 		const Sci::Line lineEndStyled =
884 			pdoc->SciLineFromPosition(pdoc->GetEndStyled());
885 		const Sci::Position endStyled =
886 			pdoc->LineStart(lineEndStyled);
887 		DocumentLexState()->Colourise(endStyled, endStyleNeeded);
888 		return;
889 	}
890 	Editor::NotifyStyleToNeeded(endStyleNeeded);
891 }
892 
893 void ScintillaBase::NotifyLexerChanged(Document *, void *) {
894 	vs.EnsureStyle(0xff);
895 }
896 
897 sptr_t ScintillaBase::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
898 	switch (iMessage) {
899 	case SCI_AUTOCSHOW:
900 		listType = 0;
901 		AutoCompleteStart(static_cast<Sci::Position>(wParam), ConstCharPtrFromSPtr(lParam));
902 		break;
903 
904 	case SCI_AUTOCCANCEL:
905 		ac.Cancel();
906 		break;
907 
908 	case SCI_AUTOCACTIVE:
909 		return ac.Active();
910 
911 	case SCI_AUTOCPOSSTART:
912 		return ac.posStart;
913 
914 	case SCI_AUTOCCOMPLETE:
915 		AutoCompleteCompleted(0, SC_AC_COMMAND);
916 		break;
917 
918 	case SCI_AUTOCSETSEPARATOR:
919 		ac.SetSeparator(static_cast<char>(wParam));
920 		break;
921 
922 	case SCI_AUTOCGETSEPARATOR:
923 		return ac.GetSeparator();
924 
925 	case SCI_AUTOCSTOPS:
926 		ac.SetStopChars(ConstCharPtrFromSPtr(lParam));
927 		break;
928 
929 	case SCI_AUTOCSELECT:
930 		ac.Select(ConstCharPtrFromSPtr(lParam));
931 		break;
932 
933 	case SCI_AUTOCGETCURRENT:
934 		return AutoCompleteGetCurrent();
935 
936 	case SCI_AUTOCGETCURRENTTEXT:
937 		return AutoCompleteGetCurrentText(CharPtrFromSPtr(lParam));
938 
939 	case SCI_AUTOCSETCANCELATSTART:
940 		ac.cancelAtStartPos = wParam != 0;
941 		break;
942 
943 	case SCI_AUTOCGETCANCELATSTART:
944 		return ac.cancelAtStartPos;
945 
946 	case SCI_AUTOCSETFILLUPS:
947 		ac.SetFillUpChars(ConstCharPtrFromSPtr(lParam));
948 		break;
949 
950 	case SCI_AUTOCSETCHOOSESINGLE:
951 		ac.chooseSingle = wParam != 0;
952 		break;
953 
954 	case SCI_AUTOCGETCHOOSESINGLE:
955 		return ac.chooseSingle;
956 
957 	case SCI_AUTOCSETIGNORECASE:
958 		ac.ignoreCase = wParam != 0;
959 		break;
960 
961 	case SCI_AUTOCGETIGNORECASE:
962 		return ac.ignoreCase;
963 
964 	case SCI_AUTOCSETCASEINSENSITIVEBEHAVIOUR:
965 		ac.ignoreCaseBehaviour = static_cast<unsigned int>(wParam);
966 		break;
967 
968 	case SCI_AUTOCGETCASEINSENSITIVEBEHAVIOUR:
969 		return ac.ignoreCaseBehaviour;
970 
971 	case SCI_AUTOCSETMULTI:
972 		multiAutoCMode = static_cast<int>(wParam);
973 		break;
974 
975 	case SCI_AUTOCGETMULTI:
976 		return multiAutoCMode;
977 
978 	case SCI_AUTOCSETORDER:
979 		ac.autoSort = static_cast<int>(wParam);
980 		break;
981 
982 	case SCI_AUTOCGETORDER:
983 		return ac.autoSort;
984 
985 	case SCI_USERLISTSHOW:
986 		listType = static_cast<int>(wParam);
987 		AutoCompleteStart(0, ConstCharPtrFromSPtr(lParam));
988 		break;
989 
990 	case SCI_AUTOCSETAUTOHIDE:
991 		ac.autoHide = wParam != 0;
992 		break;
993 
994 	case SCI_AUTOCGETAUTOHIDE:
995 		return ac.autoHide;
996 
997 	case SCI_AUTOCSETDROPRESTOFWORD:
998 		ac.dropRestOfWord = wParam != 0;
999 		break;
1000 
1001 	case SCI_AUTOCGETDROPRESTOFWORD:
1002 		return ac.dropRestOfWord;
1003 
1004 	case SCI_AUTOCSETMAXHEIGHT:
1005 		ac.lb->SetVisibleRows(static_cast<int>(wParam));
1006 		break;
1007 
1008 	case SCI_AUTOCGETMAXHEIGHT:
1009 		return ac.lb->GetVisibleRows();
1010 
1011 	case SCI_AUTOCSETMAXWIDTH:
1012 		maxListWidth = static_cast<int>(wParam);
1013 		break;
1014 
1015 	case SCI_AUTOCGETMAXWIDTH:
1016 		return maxListWidth;
1017 
1018 	case SCI_REGISTERIMAGE:
1019 		ac.lb->RegisterImage(static_cast<int>(wParam), ConstCharPtrFromSPtr(lParam));
1020 		break;
1021 
1022 	case SCI_REGISTERRGBAIMAGE:
1023 		ac.lb->RegisterRGBAImage(static_cast<int>(wParam), static_cast<int>(sizeRGBAImage.x), static_cast<int>(sizeRGBAImage.y),
1024 			ConstUCharPtrFromSPtr(lParam));
1025 		break;
1026 
1027 	case SCI_CLEARREGISTEREDIMAGES:
1028 		ac.lb->ClearRegisteredImages();
1029 		break;
1030 
1031 	case SCI_AUTOCSETTYPESEPARATOR:
1032 		ac.SetTypesep(static_cast<char>(wParam));
1033 		break;
1034 
1035 	case SCI_AUTOCGETTYPESEPARATOR:
1036 		return ac.GetTypesep();
1037 
1038 	case SCI_CALLTIPSHOW:
1039 		CallTipShow(LocationFromPosition(wParam),
1040 			ConstCharPtrFromSPtr(lParam));
1041 		break;
1042 
1043 	case SCI_CALLTIPCANCEL:
1044 		ct.CallTipCancel();
1045 		break;
1046 
1047 	case SCI_CALLTIPACTIVE:
1048 		return ct.inCallTipMode;
1049 
1050 	case SCI_CALLTIPPOSSTART:
1051 		return ct.posStartCallTip;
1052 
1053 	case SCI_CALLTIPSETPOSSTART:
1054 		ct.posStartCallTip = wParam;
1055 		break;
1056 
1057 	case SCI_CALLTIPSETHLT:
1058 		ct.SetHighlight(wParam, lParam);
1059 		break;
1060 
1061 	case SCI_CALLTIPSETBACK:
1062 		ct.colourBG = ColourDesired(static_cast<int>(wParam));
1063 		vs.styles[STYLE_CALLTIP].back = ct.colourBG;
1064 		InvalidateStyleRedraw();
1065 		break;
1066 
1067 	case SCI_CALLTIPSETFORE:
1068 		ct.colourUnSel = ColourDesired(static_cast<int>(wParam));
1069 		vs.styles[STYLE_CALLTIP].fore = ct.colourUnSel;
1070 		InvalidateStyleRedraw();
1071 		break;
1072 
1073 	case SCI_CALLTIPSETFOREHLT:
1074 		ct.colourSel = ColourDesired(static_cast<int>(wParam));
1075 		InvalidateStyleRedraw();
1076 		break;
1077 
1078 	case SCI_CALLTIPUSESTYLE:
1079 		ct.SetTabSize(static_cast<int>(wParam));
1080 		InvalidateStyleRedraw();
1081 		break;
1082 
1083 	case SCI_CALLTIPSETPOSITION:
1084 		ct.SetPosition(wParam != 0);
1085 		InvalidateStyleRedraw();
1086 		break;
1087 
1088 	case SCI_USEPOPUP:
1089 		displayPopupMenu = static_cast<int>(wParam);
1090         menuStringTable = reinterpret_cast<std::map<std::wstring, std::wstring>*>(lParam);
1091 		break;
1092 
1093 	case SCI_SETLEXER:
1094 		DocumentLexState()->SetLexer(static_cast<int>(wParam));
1095 		break;
1096 
1097 	case SCI_GETLEXER:
1098 		return DocumentLexState()->GetIdentifier();
1099 
1100 	case SCI_SETILEXER:
1101 		DocumentLexState()->SetInstance(reinterpret_cast<ILexer5 *>(lParam));
1102 		return 0;
1103 
1104 	case SCI_COLOURISE:
1105 		if (DocumentLexState()->lexLanguage == SCLEX_CONTAINER) {
1106 			pdoc->ModifiedAt(static_cast<Sci::Position>(wParam));
1107 			NotifyStyleToNeeded((lParam == -1) ? pdoc->Length() : lParam);
1108 		} else {
1109 			DocumentLexState()->Colourise(static_cast<Sci::Position>(wParam), lParam);
1110 		}
1111 		Redraw();
1112 		break;
1113 
1114 	case SCI_SETPROPERTY:
1115 		DocumentLexState()->PropSet(ConstCharPtrFromUPtr(wParam),
1116 		          ConstCharPtrFromSPtr(lParam));
1117 		break;
1118 
1119 	case SCI_GETPROPERTY:
1120 		return StringResult(lParam, DocumentLexState()->PropGet(ConstCharPtrFromUPtr(wParam)));
1121 
1122 	case SCI_GETPROPERTYEXPANDED:
1123 		return DocumentLexState()->PropGetExpanded(ConstCharPtrFromUPtr(wParam),
1124 			CharPtrFromSPtr(lParam));
1125 
1126 	case SCI_GETPROPERTYINT:
1127 		return DocumentLexState()->PropGetInt(ConstCharPtrFromUPtr(wParam), static_cast<int>(lParam));
1128 
1129 	case SCI_SETKEYWORDS:
1130 		DocumentLexState()->SetWordList(static_cast<int>(wParam), ConstCharPtrFromSPtr(lParam));
1131 		break;
1132 
1133 	case SCI_SETLEXERLANGUAGE:
1134 		DocumentLexState()->SetLexerLanguage(ConstCharPtrFromSPtr(lParam));
1135 		break;
1136 
1137 	case SCI_GETLEXERLANGUAGE:
1138 		return StringResult(lParam, DocumentLexState()->GetName());
1139 
1140 #ifdef SCI_LEXER
1141 	case SCI_LOADLEXERLIBRARY:
1142 		ExternalLexerLoad(ConstCharPtrFromSPtr(lParam));
1143 		break;
1144 #endif
1145 
1146 	case SCI_PRIVATELEXERCALL:
1147 		return reinterpret_cast<sptr_t>(
1148 			DocumentLexState()->PrivateCall(static_cast<int>(wParam), reinterpret_cast<void *>(lParam)));
1149 
1150 #ifdef INCLUDE_DEPRECATED_FEATURES
1151 	case SCI_GETSTYLEBITSNEEDED:
1152 		return 8;
1153 #endif
1154 
1155 	case SCI_PROPERTYNAMES:
1156 		return StringResult(lParam, DocumentLexState()->PropertyNames());
1157 
1158 	case SCI_PROPERTYTYPE:
1159 		return DocumentLexState()->PropertyType(ConstCharPtrFromUPtr(wParam));
1160 
1161 	case SCI_DESCRIBEPROPERTY:
1162 		return StringResult(lParam,
1163 				    DocumentLexState()->DescribeProperty(ConstCharPtrFromUPtr(wParam)));
1164 
1165 	case SCI_DESCRIBEKEYWORDSETS:
1166 		return StringResult(lParam, DocumentLexState()->DescribeWordListSets());
1167 
1168 	case SCI_GETLINEENDTYPESSUPPORTED:
1169 		return DocumentLexState()->LineEndTypesSupported();
1170 
1171 	case SCI_ALLOCATESUBSTYLES:
1172 		return DocumentLexState()->AllocateSubStyles(static_cast<int>(wParam), static_cast<int>(lParam));
1173 
1174 	case SCI_GETSUBSTYLESSTART:
1175 		return DocumentLexState()->SubStylesStart(static_cast<int>(wParam));
1176 
1177 	case SCI_GETSUBSTYLESLENGTH:
1178 		return DocumentLexState()->SubStylesLength(static_cast<int>(wParam));
1179 
1180 	case SCI_GETSTYLEFROMSUBSTYLE:
1181 		return DocumentLexState()->StyleFromSubStyle(static_cast<int>(wParam));
1182 
1183 	case SCI_GETPRIMARYSTYLEFROMSTYLE:
1184 		return DocumentLexState()->PrimaryStyleFromStyle(static_cast<int>(wParam));
1185 
1186 	case SCI_FREESUBSTYLES:
1187 		DocumentLexState()->FreeSubStyles();
1188 		break;
1189 
1190 	case SCI_SETIDENTIFIERS:
1191 		DocumentLexState()->SetIdentifiers(static_cast<int>(wParam),
1192 						   ConstCharPtrFromSPtr(lParam));
1193 		break;
1194 
1195 	case SCI_DISTANCETOSECONDARYSTYLES:
1196 		return DocumentLexState()->DistanceToSecondaryStyles();
1197 
1198 	case SCI_GETSUBSTYLEBASES:
1199 		return StringResult(lParam, DocumentLexState()->GetSubStyleBases());
1200 
1201 	case SCI_GETNAMEDSTYLES:
1202 		return DocumentLexState()->NamedStyles();
1203 
1204 	case SCI_NAMEOFSTYLE:
1205 		return StringResult(lParam, DocumentLexState()->
1206 				    NameOfStyle(static_cast<int>(wParam)));
1207 
1208 	case SCI_TAGSOFSTYLE:
1209 		return StringResult(lParam, DocumentLexState()->
1210 				    TagsOfStyle(static_cast<int>(wParam)));
1211 
1212 	case SCI_DESCRIPTIONOFSTYLE:
1213 		return StringResult(lParam, DocumentLexState()->
1214 				    DescriptionOfStyle(static_cast<int>(wParam)));
1215 
1216 	default:
1217 		return Editor::WndProc(iMessage, wParam, lParam);
1218 	}
1219 	return 0;
1220 }
1221