7#include "ontheflycheck.h"
9#include <QRegularExpression>
12#include "katebuffer.h"
13#include "kateconfig.h"
14#include "kateglobal.h"
15#include "katepartdebug.h"
17#include "spellcheck.h"
18#include "spellingmenu.h"
20#define ON_THE_FLY_DEBUG qCDebug(LOG_KTE)
24inline const QPair<KTextEditor::MovingRange *, QString> &invalidSpellCheckQueueItem()
26 static const auto item = QPair<KTextEditor::MovingRange *, QString>(
nullptr,
QString());
34 , m_document(document)
35 , m_backgroundChecker(nullptr)
36 , m_currentlyCheckedItem(invalidSpellCheckQueueItem())
37 , m_refreshView(nullptr)
39 ON_THE_FLY_DEBUG <<
"created";
41 m_viewRefreshTimer =
new QTimer(
this);
42 m_viewRefreshTimer->setSingleShot(
true);
43 connect(m_viewRefreshTimer, &
QTimer::timeout,
this, &KateOnTheFlyChecker::viewRefreshTimeout);
49 connect(&document->
buffer(), &KateBuffer::respellCheckBlock,
this, &KateOnTheFlyChecker::handleRespellCheckBlock);
58 const auto views = document->
views();
60 addView(document, view);
65KateOnTheFlyChecker::~KateOnTheFlyChecker()
70QPair<KTextEditor::Range, QString> KateOnTheFlyChecker::getMisspelledItem(
const KTextEditor::Cursor cursor)
const
72 for (
const MisspelledItem &item : m_misspelledList) {
73 KTextEditor::MovingRange *movingRange = item.first;
75 return QPair<KTextEditor::Range, QString>(*movingRange, item.second);
83 for (
const MisspelledItem &item : m_misspelledList) {
84 KTextEditor::MovingRange *movingRange = item.first;
85 if (*movingRange == range) {
92void KateOnTheFlyChecker::clearMisspellingForWord(
const QString &word)
94 const MisspelledList misspelledList = m_misspelledList;
95 for (
const MisspelledItem &item : misspelledList) {
96 KTextEditor::MovingRange *movingRange = item.first;
97 if (m_document->text(*movingRange) == word) {
98 deleteMovingRange(movingRange);
103void KateOnTheFlyChecker::handleRespellCheckBlock(
int start,
int end)
106 KTextEditor::Range range(
start, 0, end, m_document->lineLength(end));
107 bool listEmpty = m_modificationList.isEmpty();
108 KTextEditor::MovingRange *movingRange = m_document->newMovingRange(range);
111 m_modificationList.push_back(ModificationItem(TEXT_INSERTED, movingRange));
112 ON_THE_FLY_DEBUG <<
"added" << *movingRange;
120 Q_ASSERT(document == m_document);
126 bool listEmptyAtStart = m_modificationList.isEmpty();
129 const KTextEditor::Range documentIntersection = m_document->documentRange().intersect(range);
130 if (!documentIntersection.
isValid()) {
134 const auto views = m_document->views();
135 for (KTextEditor::View *i : views) {
136 KTextEditor::ViewPrivate *view =
static_cast<KTextEditor::ViewPrivate *
>(i);
137 KTextEditor::Range visibleIntersection = documentIntersection.
intersect(view->visibleRange());
138 if (visibleIntersection.
isValid()) {
140 KTextEditor::MovingRange *movingRange = m_document->newMovingRange(visibleIntersection);
142 m_modificationList.push_back(ModificationItem(TEXT_INSERTED, movingRange));
143 ON_THE_FLY_DEBUG <<
"added" << *movingRange;
147 if (listEmptyAtStart && !m_modificationList.isEmpty()) {
154 KTextEditor::Range consideredRange = range;
155 ON_THE_FLY_DEBUG << m_document << range;
157 bool spellCheckInProgress = m_currentlyCheckedItem != invalidSpellCheckQueueItem();
159 if (spellCheckInProgress) {
160 KTextEditor::MovingRange *spellCheckRange = m_currentlyCheckedItem.first;
161 if (spellCheckRange->
contains(consideredRange)) {
162 consideredRange = *spellCheckRange;
163 stopCurrentSpellCheck();
164 deleteMovingRangeQuickly(spellCheckRange);
165 }
else if (consideredRange.
contains(*spellCheckRange)) {
166 stopCurrentSpellCheck();
167 deleteMovingRangeQuickly(spellCheckRange);
168 }
else if (consideredRange.
overlaps(*spellCheckRange)) {
170 stopCurrentSpellCheck();
171 deleteMovingRangeQuickly(spellCheckRange);
173 spellCheckInProgress =
false;
176 for (QList<SpellCheckItem>::iterator i = m_spellCheckQueue.begin(); i != m_spellCheckQueue.end();) {
177 KTextEditor::MovingRange *spellCheckRange = (*i).first;
178 if (spellCheckRange->
contains(consideredRange)) {
179 consideredRange = *spellCheckRange;
180 ON_THE_FLY_DEBUG <<
"erasing range " << *i;
181 i = m_spellCheckQueue.erase(i);
182 deleteMovingRangeQuickly(spellCheckRange);
183 }
else if (consideredRange.
contains(*spellCheckRange)) {
184 ON_THE_FLY_DEBUG <<
"erasing range " << *i;
185 i = m_spellCheckQueue.erase(i);
186 deleteMovingRangeQuickly(spellCheckRange);
187 }
else if (consideredRange.
overlaps(*spellCheckRange)) {
189 ON_THE_FLY_DEBUG <<
"erasing range " << *i;
190 i = m_spellCheckQueue.erase(i);
191 deleteMovingRangeQuickly(spellCheckRange);
196 KTextEditor::Range spellCheckRange = findWordBoundaries(consideredRange.
start(), consideredRange.
end());
197 const bool emptyAtStart = m_spellCheckQueue.isEmpty();
199 queueSpellCheckVisibleRange(spellCheckRange);
201 if (spellCheckInProgress || (emptyAtStart && !m_spellCheckQueue.isEmpty())) {
208 Q_ASSERT(document == m_document);
214 bool listEmptyAtStart = m_modificationList.isEmpty();
217 const KTextEditor::Range documentIntersection = m_document->documentRange().
intersect(range);
218 if (!documentIntersection.
isValid()) {
223 const auto views = m_document->views();
224 for (KTextEditor::View *i : views) {
225 KTextEditor::ViewPrivate *view =
static_cast<KTextEditor::ViewPrivate *
>(i);
226 KTextEditor::Range visibleIntersection = documentIntersection.
intersect(view->visibleRange());
227 if (visibleIntersection.
isValid()) {
229 KTextEditor::MovingRange *movingRange = m_document->newMovingRange(visibleIntersection);
231 m_modificationList.push_back(ModificationItem(TEXT_REMOVED, movingRange));
232 ON_THE_FLY_DEBUG <<
"added" << *movingRange << view->visibleRange();
235 if (listEmptyAtStart && !m_modificationList.isEmpty()) {
247 ON_THE_FLY_DEBUG << range;
249 QList<KTextEditor::Range> rangesToReCheck;
250 for (QList<SpellCheckItem>::iterator i = m_spellCheckQueue.begin(); i != m_spellCheckQueue.end();) {
251 KTextEditor::MovingRange *spellCheckRange = (*i).first;
252 if (rangesAdjacent(*spellCheckRange, range) || spellCheckRange->
contains(range)) {
253 ON_THE_FLY_DEBUG <<
"erasing range " << *i;
254 if (!spellCheckRange->
isEmpty()) {
255 rangesToReCheck.
push_back(*spellCheckRange);
257 deleteMovingRangeQuickly(spellCheckRange);
258 i = m_spellCheckQueue.erase(i);
263 bool spellCheckInProgress = m_currentlyCheckedItem != invalidSpellCheckQueueItem();
264 const bool emptyAtStart = m_spellCheckQueue.isEmpty();
265 if (spellCheckInProgress) {
266 KTextEditor::MovingRange *spellCheckRange = m_currentlyCheckedItem.first;
267 ON_THE_FLY_DEBUG << *spellCheckRange;
268 if (m_document->documentRange().contains(*spellCheckRange) && (rangesAdjacent(*spellCheckRange, range) || spellCheckRange->
contains(range))
269 && !spellCheckRange->
isEmpty()) {
270 rangesToReCheck.
push_back(*spellCheckRange);
271 ON_THE_FLY_DEBUG <<
"added the range " << *spellCheckRange;
272 stopCurrentSpellCheck();
273 deleteMovingRangeQuickly(spellCheckRange);
274 }
else if (spellCheckRange->
isEmpty()) {
275 stopCurrentSpellCheck();
276 deleteMovingRangeQuickly(spellCheckRange);
278 spellCheckInProgress =
false;
281 for (QList<KTextEditor::Range>::iterator i = rangesToReCheck.
begin(); i != rangesToReCheck.
end(); ++i) {
282 queueSpellCheckVisibleRange(*i);
285 KTextEditor::Range spellCheckRange = findWordBoundaries(range.
start(), range.
start());
286 KTextEditor::Cursor spellCheckEnd = spellCheckRange.
end();
288 queueSpellCheckVisibleRange(spellCheckRange);
293 KTextEditor::Cursor nextLineStart(spellCheckEnd.
line() + 1, 0);
294 const KTextEditor::Cursor documentEnd = m_document->documentEnd();
295 if (nextLineStart < documentEnd) {
296 KTextEditor::Range rangeBelow = KTextEditor::Range(nextLineStart, documentEnd);
298 const QList<KTextEditor::View *> &viewList = m_document->views();
299 for (QList<KTextEditor::View *>::const_iterator i = viewList.
begin(); i != viewList.
end(); ++i) {
300 KTextEditor::ViewPrivate *view =
static_cast<KTextEditor::ViewPrivate *
>(*i);
301 const KTextEditor::Range visibleRange = view->visibleRange();
302 KTextEditor::Range intersection = visibleRange.
intersect(rangeBelow);
304 queueSpellCheckVisibleRange(view, intersection);
310 ON_THE_FLY_DEBUG <<
"finished";
311 if (spellCheckInProgress || (emptyAtStart && !m_spellCheckQueue.isEmpty())) {
316void KateOnTheFlyChecker::freeDocument()
321 for (QList<SpellCheckItem>::iterator i = m_spellCheckQueue.begin(); i != m_spellCheckQueue.end();) {
322 ON_THE_FLY_DEBUG <<
"erasing range " << *i;
323 KTextEditor::MovingRange *movingRange = (*i).first;
324 deleteMovingRangeQuickly(movingRange);
325 i = m_spellCheckQueue.erase(i);
327 if (m_currentlyCheckedItem != invalidSpellCheckQueueItem()) {
328 KTextEditor::MovingRange *movingRange = m_currentlyCheckedItem.first;
329 deleteMovingRangeQuickly(movingRange);
331 stopCurrentSpellCheck();
333 const MisspelledList misspelledList = m_misspelledList;
334 for (
const MisspelledItem &i : misspelledList) {
335 deleteMovingRange(i.first);
337 m_misspelledList.clear();
338 clearModificationList();
341void KateOnTheFlyChecker::performSpellCheck()
343 if (m_currentlyCheckedItem != invalidSpellCheckQueueItem()) {
344 ON_THE_FLY_DEBUG <<
"exited as a check is currently in progress";
347 if (m_spellCheckQueue.isEmpty()) {
348 ON_THE_FLY_DEBUG <<
"exited as there is nothing to do";
351 m_currentlyCheckedItem = m_spellCheckQueue.takeFirst();
353 KTextEditor::MovingRange *spellCheckRange = m_currentlyCheckedItem.first;
354 const QString &language = m_currentlyCheckedItem.second;
355 ON_THE_FLY_DEBUG <<
"for the range " << *spellCheckRange;
358 const MovingRangeList highlightsList = installedMovingRanges(*spellCheckRange);
359 deleteMovingRanges(highlightsList);
361 m_currentDecToEncOffsetList.clear();
362 KTextEditor::DocumentPrivate::OffsetList encToDecOffsetList;
363 QString text = m_document->decodeCharacters(*spellCheckRange, m_currentDecToEncOffsetList, encToDecOffsetList);
364 ON_THE_FLY_DEBUG <<
"next spell checking" << text;
365 if (text.isEmpty()) {
369 if (m_speller.language() != language) {
370 m_speller.setLanguage(language);
372 if (!m_backgroundChecker) {
373 m_backgroundChecker =
new Sonnet::BackgroundChecker(m_speller,
this);
378 connect(m_spellCheckManager, &KateSpellCheckManager::wordAddedToDictionary,
this, &KateOnTheFlyChecker::addToDictionary);
379 connect(m_spellCheckManager, &KateSpellCheckManager::wordIgnored,
this, &KateOnTheFlyChecker::addToSession);
381 m_backgroundChecker->setSpeller(m_speller);
382 m_backgroundChecker->setText(text);
385void KateOnTheFlyChecker::addToDictionary(
const QString &word)
387 if (m_backgroundChecker) {
388 m_backgroundChecker->addWordToPersonal(word);
392void KateOnTheFlyChecker::addToSession(
const QString &word)
394 if (m_backgroundChecker) {
395 m_backgroundChecker->addWordToSession(word);
401 Q_ASSERT(m_document == movingRange->
document());
402 ON_THE_FLY_DEBUG << *movingRange <<
"(" << movingRange <<
")";
404 if (removeRangeFromModificationList(movingRange)) {
409 if (removeRangeFromSpellCheckQueue(movingRange)) {
414 for (MisspelledList::iterator i = m_misspelledList.begin(); i != m_misspelledList.end();) {
415 if ((*i).first == movingRange) {
416 i = m_misspelledList.erase(i);
425 if (m_currentlyCheckedItem != invalidSpellCheckQueueItem() && m_currentlyCheckedItem.first == range) {
426 stopCurrentSpellCheck();
432void KateOnTheFlyChecker::stopCurrentSpellCheck()
434 m_currentDecToEncOffsetList.clear();
435 m_currentlyCheckedItem = invalidSpellCheckQueueItem();
436 if (m_backgroundChecker) {
437 m_backgroundChecker->stop();
443 if (removeRangeFromCurrentSpellCheck(range)) {
444 if (!m_spellCheckQueue.isEmpty()) {
450 for (QList<SpellCheckItem>::iterator i = m_spellCheckQueue.begin(); i != m_spellCheckQueue.end();) {
451 if ((*i).first == range) {
452 i = m_spellCheckQueue.erase(i);
463 ON_THE_FLY_DEBUG << range->
start() << range->
end() <<
"(" << range <<
")";
464 deleteMovingRange(range);
469 ON_THE_FLY_DEBUG << range->
start() << range->
end() <<
"(" << range <<
")";
470 deleteMovingRange(range);
479 KTextEditor::ViewPrivate *kateView =
static_cast<KTextEditor::ViewPrivate *
>(view);
480 kateView->spellingMenu()->caretEnteredMisspelledRange(range);
485 KTextEditor::ViewPrivate *kateView =
static_cast<KTextEditor::ViewPrivate *
>(view);
486 kateView->spellingMenu()->caretExitedMisspelledRange(range);
491 ON_THE_FLY_DEBUG << range;
493 removeRangeFromEverything(range);
495 const auto views = m_document->views();
496 for (KTextEditor::View *view : views) {
497 static_cast<KTextEditor::ViewPrivate *
>(view)->spellingMenu()->rangeDeleted(range);
504 for (KTextEditor::MovingRange *r : list) {
505 deleteMovingRange(r);
518 KTextEditor::DocumentPrivate::OffsetList decToEncOffsetList;
519 KTextEditor::DocumentPrivate::OffsetList encToDecOffsetList;
520 const int startLine =
begin.line();
521 const int startColumn =
begin.column();
522 KTextEditor::Cursor boundaryStart;
523 KTextEditor::Cursor boundaryEnd;
525 const KTextEditor::Range startLineRange(startLine, 0, startLine, m_document->lineLength(startLine));
526 QString decodedLineText = m_document->decodeCharacters(startLineRange, decToEncOffsetList, encToDecOffsetList);
527 int translatedColumn = m_document->computePositionWrtOffsets(encToDecOffsetList, startColumn);
528 QString text = decodedLineText.
mid(0, translatedColumn);
529 boundaryStart.
setLine(startLine);
534 boundaryStart.
setColumn(m_document->computePositionWrtOffsets(decToEncOffsetList, qMax(0, match)));
536 const int endLine =
end.line();
537 const int endColumn =
end.column();
538 if (endLine != startLine) {
539 decToEncOffsetList.
clear();
540 encToDecOffsetList.
clear();
541 const KTextEditor::Range endLineRange(endLine, 0, endLine, m_document->lineLength(endLine));
542 decodedLineText = m_document->decodeCharacters(endLineRange, decToEncOffsetList, encToDecOffsetList);
544 translatedColumn = m_document->computePositionWrtOffsets(encToDecOffsetList, endColumn);
545 text = decodedLineText.
mid(translatedColumn);
548 QRegularExpressionMatch reMatch;
549 match = text.
indexOf(extendedBoundaryQuoteRegExp, 0 , &reMatch);
555 boundaryEnd.
setColumn(m_document->computePositionWrtOffsets(decToEncOffsetList, translatedColumn + qMax(0, match)));
556 return KTextEditor::Range(boundaryStart, boundaryEnd);
559void KateOnTheFlyChecker::misspelling(
const QString &word,
int start)
561 if (m_currentlyCheckedItem == invalidSpellCheckQueueItem()) {
562 ON_THE_FLY_DEBUG <<
"exited as no spell check is taking place";
565 int translatedStart = m_document->computePositionWrtOffsets(m_currentDecToEncOffsetList,
start);
571 KTextEditor::MovingRange *spellCheckRange = m_currentlyCheckedItem.first;
572 int line = spellCheckRange->
start().
line();
573 int rangeStart = spellCheckRange->
start().
column();
574 int translatedEnd = m_document->computePositionWrtOffsets(m_currentDecToEncOffsetList,
start + word.
length());
576 KTextEditor::MovingRange *movingRange =
577 m_document->newMovingRange(KTextEditor::Range(line, rangeStart + translatedStart, line, rangeStart + translatedEnd));
579 KTextEditor::Attribute *attribute =
new KTextEditor::Attribute();
581 attribute->
setUnderlineColor(KateRendererConfig::global()->spellingMistakeLineColor());
587 m_misspelledList.push_back(MisspelledItem(movingRange, m_currentlyCheckedItem.second));
589 if (m_backgroundChecker) {
590 m_backgroundChecker->continueChecking();
594void KateOnTheFlyChecker::spellCheckDone()
596 ON_THE_FLY_DEBUG <<
"on-the-fly spell check done, queue length " << m_spellCheckQueue.size();
597 if (m_currentlyCheckedItem == invalidSpellCheckQueueItem()) {
600 KTextEditor::MovingRange *movingRange = m_currentlyCheckedItem.first;
601 stopCurrentSpellCheck();
602 deleteMovingRangeQuickly(movingRange);
604 if (!m_spellCheckQueue.empty()) {
611 ON_THE_FLY_DEBUG << range;
612 MovingRangeList toReturn;
614 for (QList<SpellCheckItem>::const_iterator i = m_misspelledList.begin(); i != m_misspelledList.end(); ++i) {
615 KTextEditor::MovingRange *movingRange = (*i).first;
617 toReturn.push_back(movingRange);
623void KateOnTheFlyChecker::updateConfig()
632 textInserted(m_document, range);
635 textInserted(m_document, m_document->documentRange());
641 Q_ASSERT(document == m_document);
644 auto *viewPrivate =
static_cast<KTextEditor::ViewPrivate *
>(view);
647 updateInstalledMovingRanges(
static_cast<KTextEditor::ViewPrivate *
>(view));
650void KateOnTheFlyChecker::viewDestroyed(
QObject *obj)
653 KTextEditor::View *view =
static_cast<KTextEditor::View *
>(obj);
654 m_displayRangeMap.erase(view);
660 m_displayRangeMap.erase(view);
665 Q_ASSERT(m_document == view->
document());
667 KTextEditor::Range oldDisplayRange = m_displayRangeMap[view];
669 KTextEditor::Range newDisplayRange =
static_cast<KTextEditor::ViewPrivate *
>(view)->visibleRange();
670 ON_THE_FLY_DEBUG <<
"new range: " << newDisplayRange;
671 ON_THE_FLY_DEBUG <<
"old range: " << oldDisplayRange;
672 QList<KTextEditor::MovingRange *> toDelete;
673 for (
const MisspelledItem &item : std::as_const(m_misspelledList)) {
674 KTextEditor::MovingRange *movingRange = item.first;
675 if (!movingRange->
overlaps(newDisplayRange)) {
676 bool stillVisible =
false;
677 const auto views = m_document->views();
678 for (KTextEditor::View *it2 : views) {
679 KTextEditor::ViewPrivate *view2 =
static_cast<KTextEditor::ViewPrivate *
>(it2);
680 if (view != view2 && movingRange->
overlaps(view2->visibleRange())) {
690 deleteMovingRanges(toDelete);
691 m_displayRangeMap[view] = newDisplayRange;
692 if (oldDisplayRange.isValid()) {
693 bool emptyAtStart = m_spellCheckQueue.empty();
694 for (
int line = newDisplayRange.end().line(); line >= newDisplayRange.start().line(); --line) {
695 if (!oldDisplayRange.containsLine(line)) {
696 bool visible =
false;
697 const auto views = m_document->views();
698 for (KTextEditor::View *it2 : views) {
699 KTextEditor::ViewPrivate *view2 =
static_cast<KTextEditor::ViewPrivate *
>(it2);
700 if (view != view2 && view2->visibleRange().
containsLine(line)) {
706 queueLineSpellCheck(m_document, line);
710 if (emptyAtStart && !m_spellCheckQueue.isEmpty()) {
718 const QList<KTextEditor::View *> &viewList = m_document->views();
719 for (QList<KTextEditor::View *>::const_iterator i = viewList.
begin(); i != viewList.
end(); ++i) {
720 queueSpellCheckVisibleRange(
static_cast<KTextEditor::ViewPrivate *
>(*i), range);
724void KateOnTheFlyChecker::queueSpellCheckVisibleRange(KTextEditor::ViewPrivate *view,
KTextEditor::Range range)
726 Q_ASSERT(m_document == view->doc());
727 KTextEditor::Range visibleRange = view->visibleRange();
728 KTextEditor::Range intersection = visibleRange.
intersect(range);
735 const MovingRangeList highlightsList = installedMovingRanges(intersection);
736 deleteMovingRanges(highlightsList);
738 QList<QPair<KTextEditor::Range, QString>> spellCheckRanges =
741 QListIterator<QPair<KTextEditor::Range, QString>> i(spellCheckRanges);
743 while (i.hasPrevious()) {
744 QPair<KTextEditor::Range, QString> p = i.previous();
745 queueLineSpellCheck(p.first, p.second);
751 const KTextEditor::Range range = KTextEditor::Range(line, 0, line, kateDocument->
lineLength(line));
755 const MovingRangeList highlightsList = installedMovingRanges(range);
756 deleteMovingRanges(highlightsList);
758 QList<QPair<KTextEditor::Range, QString>> spellCheckRanges =
761 QListIterator<QPair<KTextEditor::Range, QString>> i(spellCheckRanges);
763 while (i.hasPrevious()) {
764 QPair<KTextEditor::Range, QString> p = i.previous();
765 queueLineSpellCheck(p.first, p.second);
771 ON_THE_FLY_DEBUG << m_document << range;
779 addToSpellCheckQueue(range, dictionary);
784 addToSpellCheckQueue(m_document->newMovingRange(range), dictionary);
789 ON_THE_FLY_DEBUG << m_document << *range << dictionary;
794 for (QList<SpellCheckItem>::iterator i = m_spellCheckQueue.begin(); i != m_spellCheckQueue.end();) {
795 KTextEditor::MovingRange *spellCheckRange = (*i).first;
796 if (range->
contains(*spellCheckRange)) {
797 deleteMovingRangeQuickly(spellCheckRange);
798 i = m_spellCheckQueue.erase(i);
804 m_spellCheckQueue.push_front(SpellCheckItem(range, dictionary));
805 ON_THE_FLY_DEBUG <<
"added" << *range << dictionary <<
"to the queue, which has a length of" << m_spellCheckQueue.
size();
808void KateOnTheFlyChecker::viewRefreshTimeout()
811 updateInstalledMovingRanges(m_refreshView);
813 m_refreshView =
nullptr;
818 if (m_refreshView && view != m_refreshView) {
819 updateInstalledMovingRanges(m_refreshView);
821 m_refreshView = view;
822 m_viewRefreshTimer->start(100);
828 const auto views = m_document->views();
829 for (KTextEditor::View *view : views) {
830 static_cast<KTextEditor::ViewPrivate *
>(view)->spellingMenu()->rangeDeleted(range);
835void KateOnTheFlyChecker::handleModifiedRanges()
837 for (
const ModificationItem &item : std::as_const(m_modificationList)) {
838 KTextEditor::MovingRange *movingRange = item.second;
839 KTextEditor::Range range = *movingRange;
840 deleteMovingRangeQuickly(movingRange);
841 if (item.first == TEXT_INSERTED) {
842 handleInsertedText(range);
844 handleRemovedText(range);
847 m_modificationList.clear();
853 for (ModificationList::iterator i = m_modificationList.begin(); i != m_modificationList.end();) {
854 ModificationItem item = *i;
855 KTextEditor::MovingRange *movingRange = item.second;
856 if (movingRange == range) {
858 i = m_modificationList.erase(i);
866void KateOnTheFlyChecker::clearModificationList()
868 for (
const ModificationItem &item : std::as_const(m_modificationList)) {
869 KTextEditor::MovingRange *movingRange = item.second;
870 deleteMovingRangeQuickly(movingRange);
872 m_modificationList.clear();
QExplicitlySharedDataPointer< Attribute > Ptr
Shared data pointer for Attribute.
The Cursor represents a position in a Document.
void setColumn(int column) noexcept
Set the cursor column to column.
void setLine(int line) noexcept
Set the cursor line to line.
constexpr int line() const noexcept
Retrieve the line on which this cursor is situated.
Backend of KTextEditor::Document related public KTextEditor interfaces.
KateBuffer & buffer()
Get access to buffer of this document.
void textRemoved(KTextEditor::Document *document, KTextEditor::Range range, const QString &oldText)
The document emits this signal whenever range was removed, i.e.
void textInsertedRange(KTextEditor::Document *document, KTextEditor::Range range)
The document emits this signal whenever text was inserted.
QList< KTextEditor::View * > views() const override
Returns the views pre-casted to KTextEditor::Views.
int lineLength(int line) const override
Get the length of a given line in characters.
A KParts derived class representing a text document.
void reloaded(KTextEditor::Document *document)
Emitted after the current document was reloaded.
void viewCreated(KTextEditor::Document *document, KTextEditor::View *view)
This signal is emitted whenever the document creates a new view.
void highlightingModeChanged(KTextEditor::Document *document)
Warn anyone listening that the current document's highlighting mode has changed.
KateSpellCheckManager * spellCheckManager()
spell check manager
static KTextEditor::EditorPrivate * self()
Kate Part Internal stuff ;)
virtual int column() const =0
Retrieve the column on which this cursor is situated.
virtual int line() const =0
Retrieve the line on which this cursor is situated.
A range that is bound to a specific Document, and maintains its position.
virtual void setAttribute(Attribute::Ptr attribute)=0
Sets the currently active attribute for this range.
virtual const MovingCursor & start() const =0
Retrieve start cursor of this range, read-only.
virtual void setAttributeOnlyForViews(bool onlyForViews)=0
Set if this range's attribute is only visible in views, not for example prints.
bool isEmpty() const
Returns true if this range contains no characters, ie.
virtual const MovingCursor & end() const =0
Retrieve end cursor of this range, read-only.
virtual void setFeedback(MovingRangeFeedback *feedback)=0
Sets the currently active MovingRangeFeedback for this range.
virtual Document * document() const =0
Gets the document to which this range is bound.
bool contains(const Range &range) const
Check whether the this range wholly encompasses range.
bool overlaps(const Range &range) const
Check whether the this range overlaps with range.
An object representing a section of text, from one Cursor to another.
constexpr Cursor end() const noexcept
Get the end position of this range.
constexpr Cursor start() const noexcept
Get the start position of this range.
constexpr bool isEmpty() const noexcept
Returns true if this range contains no characters, ie.
constexpr bool overlaps(Range range) const noexcept
Check whether the this range overlaps with range.
constexpr bool onSingleLine() const noexcept
Check whether this range is wholly contained within one line, ie.
static constexpr Range invalid() noexcept
Returns an invalid range.
constexpr bool isValid() const noexcept
Validity check.
constexpr bool containsLine(int line) const noexcept
Returns true if this range wholly encompasses line.
constexpr bool contains(Range range) const noexcept
Check whether the this range wholly encompasses range.
bool expandToRange(Range range) noexcept
Expand this range if necessary to contain range.
constexpr Range intersect(Range range) const noexcept
Intersects this range with another, returning the shared area of the two ranges.
constexpr int numberOfLines() const noexcept
Returns the number of lines separating the start() and end() positions.
A text widget with KXMLGUIClient that represents a Document.
void displayRangeChanged(KTextEditor::View *view)
This signal is emitted whenever the displayed range changes.
virtual Document * document() const =0
Get the view's document, that means the view is a view of the returned document.
void misspelling(const QString &word, int start)
Q_SCRIPTABLE QString start(QString train="")
Q_SCRIPTABLE Q_NOREPLY void start()
KCOREADDONS_EXPORT Result match(QStringView pattern, QStringView str)
const QList< QKeySequence > & begin()
const QList< QKeySequence > & end()
void push_back(parameter_type value)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void destroyed(QObject *obj)
UseUnicodePropertiesOption
qsizetype capturedLength(QStringView name) const const
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
qsizetype lastIndexOf(QChar ch, Qt::CaseSensitivity cs) const const
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) const const
qsizetype size() const const
void setUnderlineColor(const QColor &color)
void setUnderlineStyle(UnderlineStyle style)