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