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