From df980c1f3747a55c77e3316e18226e078369312a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20K=C3=BCng?= Date: Sat, 16 Mar 2024 10:22:31 +0100 Subject: [PATCH] skip over whitespaces first before finding the word start position to avoid breaking out of the spell check loop closes #368 --- src/Commands/CmdSpellcheck.cpp | 45 ++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/src/Commands/CmdSpellcheck.cpp b/src/Commands/CmdSpellcheck.cpp index 0f09c224..6a9326da 100644 --- a/src/Commands/CmdSpellcheck.cpp +++ b/src/Commands/CmdSpellcheck.cpp @@ -160,6 +160,7 @@ void CCmdSpellCheck::Check() #ifdef _DEBUG ProfileTimer timer(L"SpellCheck"); #endif + // determine the spelling options for the current lexer and settings bool checkAll = CIniSettings::Instance().GetInt64(L"spellcheck", L"checkall", 1) != 0; bool checkUppercase = CIniSettings::Instance().GetInt64(L"spellcheck", L"uppercase", 1) != 0; if (m_activeLexer != static_cast(Scintilla().Lexer())) @@ -183,16 +184,18 @@ void CCmdSpellCheck::Check() Scintilla().SetWordChars(g_sentenceChars.c_str()); else Scintilla().SetWordChars(g_wordChars.c_str()); + // start at the first visible line and check all visible lines Scintilla::TextRangeFull textRange{}; - auto firstLine = Scintilla().FirstVisibleLine(); - auto lastLine = firstLine + Scintilla().LinesOnScreen(); - auto firstPos = static_cast(Scintilla().PositionFromLine(firstLine)); - textRange.chrg.cpMin = firstPos; - textRange.chrg.cpMax = textRange.chrg.cpMin; - auto lastPos = Scintilla().PositionFromLine(lastLine) + Scintilla().LineLength(lastLine); - auto textLength = Scintilla().Length(); + auto firstLine = Scintilla().FirstVisibleLine(); + auto lastLine = firstLine + Scintilla().LinesOnScreen(); + auto firstPos = static_cast(Scintilla().PositionFromLine(firstLine)); + textRange.chrg.cpMin = firstPos; + textRange.chrg.cpMax = textRange.chrg.cpMin; + auto lastPos = Scintilla().PositionFromLine(lastLine) + Scintilla().LineLength(lastLine); + auto textLength = Scintilla().Length(); if (lastPos < 0) lastPos = textLength - textRange.chrg.cpMin; + // if we already checked some text of the visible lines, start from there if (m_lastCheckedPos) textRange.chrg.cpMax = static_cast(m_lastCheckedPos); auto start = GetTickCount64(); @@ -200,22 +203,38 @@ void CCmdSpellCheck::Check() { if (GetTickCount64() - start > 100) { + // to avoid a blocked UI, only check for 100ms and then continue later m_lastCheckedPos = textRange.chrg.cpMax; if (g_checkTimer) SetTimer(GetHwnd(), g_checkTimer, 10, nullptr); break; } + // split the whole text either into words or if m_useComprehensiveCheck is true into sentences Scintilla().SetWordChars(g_wordChars.c_str()); + // skip over whitespace + while (textRange.chrg.cpMax < lastPos) + { + auto c = Scintilla().CharacterAt(textRange.chrg.cpMax); + if (c > 0x20) + break; + textRange.chrg.cpMax++; + } + // don't start in the middle of a word but at the beginning textRange.chrg.cpMin = static_cast(Scintilla().WordStartPosition(textRange.chrg.cpMax + 1, TRUE)); - if (m_useComprehensiveCheck) - Scintilla().SetWordChars(g_sentenceChars.c_str()); - else - Scintilla().SetWordChars(g_wordChars.c_str()); if (textRange.chrg.cpMin < textRange.chrg.cpMax && textRange.chrg.cpMin >= firstPos) { - DebugBreak(); - break; + // word start is before the visible text, so we skip it + auto wordEnd = static_cast(Scintilla().WordEndPosition(textRange.chrg.cpMax, TRUE)); + if (wordEnd <= textRange.chrg.cpMax) + { + DebugBreak(); + break; + } + textRange.chrg.cpMax = wordEnd; + continue; } + if (m_useComprehensiveCheck) + Scintilla().SetWordChars(g_sentenceChars.c_str()); textRange.chrg.cpMax = static_cast(Scintilla().WordEndPosition(textRange.chrg.cpMin, TRUE)); if (textRange.chrg.cpMax > lastPos) {