mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-23 18:32:49 +00:00
kdeui: KSpeller and KSpellHighlighter optimization
2x to 3x faster on practical test cases Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
parent
e774460cf3
commit
802b68d0a3
3 changed files with 81 additions and 69 deletions
|
@ -21,7 +21,6 @@
|
|||
#include "kdebug.h"
|
||||
|
||||
#include <QLocale>
|
||||
#include <QTextBoundaryFinder>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <enchant.h>
|
||||
|
@ -271,43 +270,27 @@ void KSpeller::start()
|
|||
{
|
||||
// qDebug() << Q_FUNC_INFO << d->text.size() << d->text;
|
||||
d->interrupt = false;
|
||||
int wordstart = 0;
|
||||
QTextBoundaryFinder finder(QTextBoundaryFinder::Word, d->text);
|
||||
while (finder.toNextBoundary() >= 0) {
|
||||
int wordstart = -1;
|
||||
int counter = 0;
|
||||
while (counter < d->text.size()) {
|
||||
if (d->interrupt) {
|
||||
break;
|
||||
}
|
||||
const QTextBoundaryFinder::BoundaryReasons boundary = finder.boundaryReasons();
|
||||
if (boundary & QTextBoundaryFinder::StartWord) {
|
||||
wordstart = finder.position();
|
||||
}
|
||||
if (boundary & QTextBoundaryFinder::EndWord) {
|
||||
QString word = d->text.mid(wordstart, finder.position() - wordstart);
|
||||
|
||||
// remove whitespace at the start and end
|
||||
while (!word.isEmpty() && word.at(0).isSpace()) {
|
||||
word = word.mid(1, word.size() - 1);
|
||||
wordstart++;
|
||||
}
|
||||
while (!word.isEmpty() && word.at(word.size() - 1).isSpace()) {
|
||||
word = word.mid(0, word.size() - 1);
|
||||
}
|
||||
|
||||
// chop punctuation
|
||||
if (!word.isEmpty() && word.at(word.size() - 1).isPunct()) {
|
||||
word = word.mid(0, word.size() - 1);
|
||||
}
|
||||
|
||||
const bool atseparator = KSpeller::isWordSeparator(d->text.at(counter));
|
||||
if (!atseparator && wordstart == -1) {
|
||||
wordstart = counter;
|
||||
} else if (atseparator && wordstart != -1) {
|
||||
const QString word = d->text.mid(wordstart, counter - wordstart);
|
||||
// not worth checking if it is less than two characters
|
||||
if (word.size() < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// qDebug() << Q_FUNC_INFO << boundary << wordstart << finder.position() << word;
|
||||
if (!check(word)) {
|
||||
emit misspelling(word, wordstart);
|
||||
if (word.size() >= 2) {
|
||||
// qDebug() << Q_FUNC_INFO << wordstart << counter << word;
|
||||
if (!check(word)) {
|
||||
emit misspelling(word, wordstart);
|
||||
}
|
||||
}
|
||||
wordstart = -1;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
emit done();
|
||||
}
|
||||
|
@ -317,4 +300,47 @@ void KSpeller::stop()
|
|||
d->interrupt = true;
|
||||
}
|
||||
|
||||
// the code is similar to the code in QTextEngine on purpose, kate uses different logic for
|
||||
// selection tho
|
||||
bool KSpeller::isWordSeparator(const QChar c)
|
||||
{
|
||||
switch (c.toLatin1()) {
|
||||
case '.':
|
||||
case ',':
|
||||
case '?':
|
||||
case '!':
|
||||
case '@':
|
||||
case '#':
|
||||
case '$':
|
||||
case ':':
|
||||
case ';':
|
||||
case '-':
|
||||
case '<':
|
||||
case '>':
|
||||
case '[':
|
||||
case ']':
|
||||
case '(':
|
||||
case ')':
|
||||
case '{':
|
||||
case '}':
|
||||
case '=':
|
||||
case '/':
|
||||
case '+':
|
||||
case '%':
|
||||
case '&':
|
||||
case '^':
|
||||
case '*':
|
||||
case '\'':
|
||||
case '"':
|
||||
case '`':
|
||||
case '~':
|
||||
case '|': {
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
return c.isSpace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_kspeller.cpp"
|
||||
|
|
|
@ -52,6 +52,7 @@ public:
|
|||
bool removeFromSession(const QString &word);
|
||||
|
||||
static QString defaultLanguage();
|
||||
static bool isWordSeparator(const QChar c);
|
||||
|
||||
void setText(const QString &text);
|
||||
QString text() const;
|
||||
|
|
|
@ -21,24 +21,24 @@
|
|||
#include "kcolorscheme.h"
|
||||
#include "kdebug.h"
|
||||
|
||||
#include <QTextBoundaryFinder>
|
||||
|
||||
class KSpellHighlighterPrivate
|
||||
{
|
||||
public:
|
||||
KSpellHighlighterPrivate(KConfig *config);
|
||||
|
||||
KSpeller speller;
|
||||
QTextCharFormat charformat;
|
||||
QTextCharFormat emptyformat;
|
||||
QTextCharFormat spellformat;
|
||||
|
||||
};
|
||||
|
||||
KSpellHighlighterPrivate::KSpellHighlighterPrivate(KConfig *config)
|
||||
: speller(config)
|
||||
{
|
||||
charformat.setFontUnderline(true);
|
||||
charformat.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline);
|
||||
spellformat.setFontUnderline(true);
|
||||
spellformat.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline);
|
||||
// NOTE: same as the default of Kate
|
||||
charformat.setUnderlineColor(KColorScheme(QPalette::Active, KColorScheme::View).foreground(KColorScheme::NegativeText).color());
|
||||
spellformat.setUnderlineColor(KColorScheme(QPalette::Active, KColorScheme::View).foreground(KColorScheme::NegativeText).color());
|
||||
}
|
||||
|
||||
KSpellHighlighter::KSpellHighlighter(KConfig *config, QTextEdit *parent)
|
||||
|
@ -93,41 +93,26 @@ void KSpellHighlighter::highlightBlock(const QString &text)
|
|||
if (text.isEmpty() || d->speller.dictionary().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
int wordstart = 0;
|
||||
QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
|
||||
while (finder.toNextBoundary() >= 0) {
|
||||
const QTextBoundaryFinder::BoundaryReasons boundary = finder.boundaryReasons();
|
||||
if (boundary & QTextBoundaryFinder::StartWord) {
|
||||
wordstart = finder.position();
|
||||
}
|
||||
if (boundary & QTextBoundaryFinder::EndWord) {
|
||||
QString word = text.mid(wordstart, finder.position() - wordstart);
|
||||
|
||||
// remove whitespace at the start and end
|
||||
while (!word.isEmpty() && word.at(0).isSpace()) {
|
||||
word = word.mid(1, word.size() - 1);
|
||||
wordstart++;
|
||||
}
|
||||
while (!word.isEmpty() && word.at(word.size() - 1).isSpace()) {
|
||||
word = word.mid(0, word.size() - 1);
|
||||
}
|
||||
|
||||
// chop punctuation
|
||||
if (!word.isEmpty() && word.at(word.size() - 1).isPunct()) {
|
||||
word = word.mid(0, word.size() - 1);
|
||||
}
|
||||
|
||||
int wordstart = -1;
|
||||
int counter = 0;
|
||||
while (counter < text.size()) {
|
||||
const bool atseparator = KSpeller::isWordSeparator(text.at(counter));
|
||||
if (!atseparator && wordstart == -1) {
|
||||
wordstart = counter;
|
||||
} else if (atseparator && wordstart != -1) {
|
||||
const QString word = text.mid(wordstart, counter - wordstart);
|
||||
// not worth checking if it is less than two characters
|
||||
if (word.size() < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!d->speller.check(word)) {
|
||||
setFormat(wordstart, word.size(), d->charformat);
|
||||
} else {
|
||||
setFormat(wordstart, word.size(), QTextCharFormat());
|
||||
if (word.size() >= 2) {
|
||||
if (!d->speller.check(word)) {
|
||||
setFormat(wordstart, word.size(), d->spellformat);
|
||||
} else {
|
||||
setFormat(wordstart, word.size(), d->emptyformat);
|
||||
}
|
||||
}
|
||||
wordstart = -1;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue