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