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
ScintillaBase()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
~ScintillaBase()78 ScintillaBase::~ScintillaBase() {
79 }
80
Finalise()81 void ScintillaBase::Finalise() {
82 Editor::Finalise();
83 popup.Destroy();
84 }
85
AddCharUTF(const char * s,unsigned int len,bool)86 void ScintillaBase::AddCharUTF(const char *s, unsigned int len, bool /*treatAsDBCS*/) {
87 InsertCharacter(std::string_view(s, len), CharacterSource::directInput);
88 }
89
InsertCharacter(std::string_view sv,CharacterSource charSource)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
Command(int cmdId)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
KeyCommand(unsigned int iMessage)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
ListNotify(ListBoxEvent * plbe)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
AutoCompleteInsert(Sci::Position startPos,Sci::Position removeLen,const char * text,Sci::Position textLen)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
AutoCompleteStart(Sci::Position lenEntered,const char * list)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
AutoCompleteCancel()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
AutoCompleteMove(int delta)346 void ScintillaBase::AutoCompleteMove(int delta) {
347 ac.Move(delta);
348 }
349
AutoCompleteMoveToCurrentWord()350 void ScintillaBase::AutoCompleteMoveToCurrentWord() {
351 std::string wordCurrent = RangeText(ac.posStart - ac.startLen, sel.MainCaret());
352 ac.Select(wordCurrent.c_str());
353 }
354
AutoCompleteSelection()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
AutoCompleteCharacterAdded(char ch)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
AutoCompleteCharacterDeleted()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
AutoCompleteCompleted(char ch,unsigned int completionMethod)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
AutoCompleteGetCurrent() const442 int ScintillaBase::AutoCompleteGetCurrent() const {
443 if (!ac.Active())
444 return -1;
445 return ac.GetSelection();
446 }
447
AutoCompleteGetCurrentText(char * buffer) const448 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
CallTipShow(Point pt,const char * defn)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
CallTipClick()504 void ScintillaBase::CallTipClick() {
505 SCNotification scn = {};
506 scn.nmhdr.code = SCN_CALLTIPCLICK;
507 scn.position = ct.clickPlace;
508 NotifyParent(scn);
509 }
510
ShouldDisplayPopup(Point ptInWindowCoordinates) const511 bool ScintillaBase::ShouldDisplayPopup(Point ptInWindowCoordinates) const {
512 return (displayPopupMenu == SC_POPUP_ALL ||
513 (displayPopupMenu == SC_POPUP_TEXT && !PointInSelMargin(ptInWindowCoordinates)));
514 }
515
ContextMenu(Point pt)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
CancelModes()550 void ScintillaBase::CancelModes() {
551 AutoCompleteCancel();
552 ct.CallTipCancel();
553 Editor::CancelModes();
554 }
555
ButtonDownWithModifiers(Point pt,unsigned int curTime,int modifiers)556 void ScintillaBase::ButtonDownWithModifiers(Point pt, unsigned int curTime, int modifiers) {
557 CancelModes();
558 Editor::ButtonDownWithModifiers(pt, curTime, modifiers);
559 }
560
RightButtonDownWithModifiers(Point pt,unsigned int curTime,int modifiers)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
LexState(Document * pdoc_)618 LexState::LexState(Document *pdoc_) : LexInterface(pdoc_) {
619 lexCurrent = nullptr;
620 performingStyle = false;
621 interfaceVersion = lvRelease4;
622 lexLanguage = SCLEX_CONTAINER;
623 }
624
~LexState()625 LexState::~LexState() {
626 if (instance) {
627 instance->Release();
628 instance = nullptr;
629 }
630 }
631
SetInstance(ILexer5 * instance_)632 void LexState::SetInstance(ILexer5 *instance_) {
633 if (instance) {
634 instance->Release();
635 instance = nullptr;
636 }
637 instance = instance_;
638 pdoc->LexerChanged();
639 }
640
DocumentLexState()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
SetLexerModule(const LexerModule * lex)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
SetLexer(uptr_t wParam)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
SetLexerLanguage(const char * languageName)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
DescribeWordListSets()685 const char *LexState::DescribeWordListSets() {
686 if (instance) {
687 return instance->DescribeWordListSets();
688 } else {
689 return nullptr;
690 }
691 }
692
SetWordList(int n,const char * wl)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
GetIdentifier() const702 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
GetName() const714 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
PrivateCall(int operation,void * pointer)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
PropertyNames()734 const char *LexState::PropertyNames() {
735 if (instance) {
736 return instance->PropertyNames();
737 } else {
738 return nullptr;
739 }
740 }
741
PropertyType(const char * name)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
DescribeProperty(const char * name)750 const char *LexState::DescribeProperty(const char *name) {
751 if (instance) {
752 return instance->DescribeProperty(name);
753 } else {
754 return nullptr;
755 }
756 }
757
PropSet(const char * key,const char * val)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
PropGet(const char * key) const768 const char *LexState::PropGet(const char *key) const {
769 return props.Get(key);
770 }
771
PropGetInt(const char * key,int defaultValue) const772 int LexState::PropGetInt(const char *key, int defaultValue) const {
773 return props.GetInt(key, defaultValue);
774 }
775
PropGetExpanded(const char * key,char * result) const776 size_t LexState::PropGetExpanded(const char *key, char *result) const {
777 return props.GetExpanded(key, result);
778 }
779
LineEndTypesSupported()780 int LexState::LineEndTypesSupported() {
781 if (instance) {
782 return instance->LineEndTypesSupported();
783 }
784 return 0;
785 }
786
AllocateSubStyles(int styleBase,int numberStyles)787 int LexState::AllocateSubStyles(int styleBase, int numberStyles) {
788 if (instance) {
789 return instance->AllocateSubStyles(styleBase, numberStyles);
790 }
791 return -1;
792 }
793
SubStylesStart(int styleBase)794 int LexState::SubStylesStart(int styleBase) {
795 if (instance) {
796 return instance->SubStylesStart(styleBase);
797 }
798 return -1;
799 }
800
SubStylesLength(int styleBase)801 int LexState::SubStylesLength(int styleBase) {
802 if (instance) {
803 return instance->SubStylesLength(styleBase);
804 }
805 return 0;
806 }
807
StyleFromSubStyle(int subStyle)808 int LexState::StyleFromSubStyle(int subStyle) {
809 if (instance) {
810 return instance->StyleFromSubStyle(subStyle);
811 }
812 return 0;
813 }
814
PrimaryStyleFromStyle(int style)815 int LexState::PrimaryStyleFromStyle(int style) {
816 if (instance) {
817 return instance->PrimaryStyleFromStyle(style);
818 }
819 return 0;
820 }
821
FreeSubStyles()822 void LexState::FreeSubStyles() {
823 if (instance) {
824 instance->FreeSubStyles();
825 }
826 }
827
SetIdentifiers(int style,const char * identifiers)828 void LexState::SetIdentifiers(int style, const char *identifiers) {
829 if (instance) {
830 instance->SetIdentifiers(style, identifiers);
831 pdoc->ModifiedAt(0);
832 }
833 }
834
DistanceToSecondaryStyles()835 int LexState::DistanceToSecondaryStyles() {
836 if (instance) {
837 return instance->DistanceToSecondaryStyles();
838 }
839 return 0;
840 }
841
GetSubStyleBases()842 const char *LexState::GetSubStyleBases() {
843 if (instance) {
844 return instance->GetSubStyleBases();
845 }
846 return "";
847 }
848
NamedStyles()849 int LexState::NamedStyles() {
850 if (instance) {
851 return instance->NamedStyles();
852 } else {
853 return -1;
854 }
855 }
856
NameOfStyle(int style)857 const char *LexState::NameOfStyle(int style) {
858 if (instance) {
859 return instance->NameOfStyle(style);
860 } else {
861 return nullptr;
862 }
863 }
864
TagsOfStyle(int style)865 const char *LexState::TagsOfStyle(int style) {
866 if (instance) {
867 return instance->TagsOfStyle(style);
868 } else {
869 return nullptr;
870 }
871 }
872
DescriptionOfStyle(int style)873 const char *LexState::DescriptionOfStyle(int style) {
874 if (instance) {
875 return instance->DescriptionOfStyle(style);
876 } else {
877 return nullptr;
878 }
879 }
880
NotifyStyleToNeeded(Sci::Position endStyleNeeded)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
NotifyLexerChanged(Document *,void *)893 void ScintillaBase::NotifyLexerChanged(Document *, void *) {
894 vs.EnsureStyle(0xff);
895 }
896
WndProc(unsigned int iMessage,uptr_t wParam,sptr_t lParam)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