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