[arch-commits] Commit in kdeplasma-addons/trunk (PKGBUILD fix-spell-crash.patch)

Andrea Scarpino andrea at archlinux.org
Wed Oct 31 10:12:24 UTC 2012


    Date: Wednesday, October 31, 2012 @ 06:12:24
  Author: andrea
Revision: 170052

upgpkg: kdeplasma-addons 4.9.2-3

Apply patch to fix the spell krunner plugin

Added:
  kdeplasma-addons/trunk/fix-spell-crash.patch
Modified:
  kdeplasma-addons/trunk/PKGBUILD

-----------------------+
 PKGBUILD              |   12 +-
 fix-spell-crash.patch |  267 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 276 insertions(+), 3 deletions(-)

Modified: PKGBUILD
===================================================================
--- PKGBUILD	2012-10-31 09:24:25 UTC (rev 170051)
+++ PKGBUILD	2012-10-31 10:12:24 UTC (rev 170052)
@@ -76,17 +76,23 @@
          'kdeplasma-addons-wallpapers-virus'
          'kdeplasma-addons-wallpapers-weather')
 pkgver=4.9.2
-pkgrel=2
+pkgrel=3
 arch=('i686' 'x86_64')
 url='http://www.kde.org'
 license=('GPL' 'LGPL')
 groups=('kde' 'kdeplasma-addons')
 makedepends=('cmake' 'automoc4' 'kdebase-workspace' 'kdeedu-marble' 'eigen'
              'scim' 'qwt' 'boost' 'libkexiv2' 'ibus' 'qoauth' 'qjson')
-source=("http://download.kde.org/stable/${pkgver}/src/${pkgbase}-${pkgver}.tar.xz")
-sha1sums=('9f6493d52beb2ed723038e60f5f9ab53beec4e44')
+source=("http://download.kde.org/stable/${pkgver}/src/${pkgbase}-${pkgver}.tar.xz"
+        'fix-spell-crash.patch')
+sha1sums=('9f6493d52beb2ed723038e60f5f9ab53beec4e44'
+          '1ff0e61d73a4fce8ee7f585504a129ff50405ae6')
 
 build() {
+    cd ${pkgbase}-${pkgver}
+    patch -p1 -i "${srcdir}"/fix-spell-crash.patch
+    cd ../
+
 	mkdir build
 	cd build
 	cmake ../${pkgbase}-${pkgver} \

Added: fix-spell-crash.patch
===================================================================
--- fix-spell-crash.patch	                        (rev 0)
+++ fix-spell-crash.patch	2012-10-31 10:12:24 UTC (rev 170052)
@@ -0,0 +1,267 @@
+commit 124e35885b8cd1b593b7b83a070bd0bdb5758661
+Author: Simeon Bird <bladud at gmail.com>
+Date:   Fri Oct 19 21:16:34 2012 -0400
+
+    Fix the plasma spellchecker's 'foreign language' support.
+    Previously this caused segfaults (even if not used) because
+    it called setLanguage(), which is not thread-safe, in match().
+    
+    Instead, this patch constructs a new speller safely for each new
+    language, without deleting the old one. Old spellers are instead
+    deleted on the teardown() signal.
+    
+    While we're at it, amend the language detection so that the user
+    can type natural language names (eg, 'german') and have the
+    spell-checker find the right language.
+    
+    REVIEW: 106244
+    BUG: 303831
+    BUG: 264779
+    FIXED-IN: 4.9.3
+
+diff --git a/runners/spellchecker/spellcheck.cpp b/runners/spellchecker/spellcheck.cpp
+index 672732d..cc6aeb2 100644
+--- a/runners/spellchecker/spellcheck.cpp
++++ b/runners/spellchecker/spellcheck.cpp
+@@ -24,6 +24,7 @@
+ // #include <KDebug>
+ #include <KGlobal>
+ #include <KIcon>
++#include <QSet>
+ 
+ SpellCheckRunner::SpellCheckRunner(QObject* parent, const QVariantList &args)
+     : Plasma::AbstractRunner(parent, args)
+@@ -43,13 +44,64 @@ void SpellCheckRunner::init()
+ {
+     Plasma::AbstractRunner::init();
+ 
+-    //store all language names, makes it posible to type "spell german TERM" if english locale is set
++    //Connect prepare and teardown signals
++    connect(this, SIGNAL(prepare()), this, SLOT(loaddata()));
++    connect(this, SIGNAL(teardown()), this, SLOT(destroydata()));
++}
++
++//Load a default dictionary and some locale names
++void SpellCheckRunner::loaddata()
++{
++    //Load the default speller, with the default language
++    if (!m_spellers.contains("")) {
++        m_spellers[""] = QSharedPointer<Sonnet::Speller> (new Sonnet::Speller(""));
++    }
++    //store all language names, makes it possible to type "spell german TERM" if english locale is set
++    //Need to construct a map between natual language names and names the spell-check recognises.
+     KLocale *locale = KGlobal::locale();
+-    QStringList codes = locale->allLanguagesList();
+-    foreach (const QString &code, codes) {
+-        const QString name = locale->languageCodeToName(code);
+-        m_languages[name.toLower()] = code;
++    const QStringList avail = m_spellers[""]->availableLanguages();
++    //We need to filter the available languages so that we associate the natural language
++    //name (eg. 'german') with one sub-code.
++    QSet<QString> families;
++    //First get the families
++    foreach (const QString &code, avail) {
++        families +=code.left(2);
++    }
++    //Now for each family figure out which is the main code.
++    foreach (const QString &fcode,families) {
++        QStringList family = avail.filter(fcode);
++        QString code;
++        //If we only have one code, use it.
++        //If a string is the default language, use it
++        if (family.contains(m_spellers[""]->language())) {
++            code = m_spellers[""]->language();
++        } else if (fcode == QLatin1String("en")) {
++            //If the family is english, default to en_US.
++            if (family.contains("en_US")) {
++                code = QLatin1String("en_US");
++            }
++        } else if (family.contains(fcode+QLatin1String("_")+fcode.toUpper())) {
++            //If we have a speller of the form xx_XX, try that.
++            //This gets us most European languages with more than one spelling.
++            code =  fcode+QLatin1String("_")+fcode.toUpper();
++        } else {
++            //Otherwise, pick the first value as it is highest priority.
++            code = family.first();
++        }
++        //Finally, add code to the map.
++        const QString name = locale->languageCodeToName(fcode);
++        if (!name.isEmpty()) {
++            m_languages[name.toLower()] = code;
++        }
++//         kDebug() << "SPELL lang: " << fcode<< "::"<< name << "  :  " << code;
+     }
++
++}
++
++void SpellCheckRunner::destroydata()
++{
++    //Clear the data arrays to save memory
++    m_spellers.clear();
+ }
+ 
+ void SpellCheckRunner::reloadConfiguration()
+@@ -73,13 +125,52 @@ void SpellCheckRunner::reloadConfiguration()
+     setSyntaxes(syns);
+ }
+ 
++/* Take the input query, split into a list, and see if it contains a language to spell in.
++ * Return the empty string if we can't match a language. */
++QString SpellCheckRunner::findlang(const QStringList& terms)
++{
++    //If first term is a language code (like en_GB), set it as the spell-check language
++    if (terms.count() >= 1 && m_spellers[""]->availableLanguages().contains(terms[0])) {
++        return terms[0];
++    }
++    //If we have two terms and the first is a language name (eg 'french'),
++    //set it as the available language
++    else if (terms.count() >=2) {
++        QString code;
++        {
++            //Is this a descriptive language name?
++            QMap<QString, QString>::const_iterator it = m_languages.constFind(terms[0].toLower());
++            if (it != m_languages.constEnd()) {
++                code = *it;
++            }
++            //Maybe it is a subset of a language code?
++            else {
++                QStringList codes = QStringList(m_languages.values()).filter(terms[0]);
++                if (!codes.isEmpty()) {
++                    code = codes.first();
++                }
++            }
++        }
++
++        if (!code.isEmpty()) {
++            //We found a valid language! Check still available
++            const QStringList avail = m_spellers[""]->availableLanguages();
++            //Does the spell-checker like it?
++            if (avail.contains(code)) {
++                return code;
++            }
++        }
++        //FIXME: Support things like 'british english' or 'canadian french'
++    }
++    return QLatin1String("");
++}
++
+ void SpellCheckRunner::match(Plasma::RunnerContext &context)
+ {
+     if (!context.isValid()) {
+         return;
+     }
+ 
+-
+     const QString term = context.query();
+     QString query = term;
+ 
+@@ -88,53 +179,46 @@ void SpellCheckRunner::match(Plasma::RunnerContext &context)
+         if (query.left(len) != m_triggerWord) {
+             return;
+         }
+-
+-        QString language = m_speller.defaultLanguage();
+         query = query.mid(len).trimmed();
+-        QStringList terms = query.split(' ');
+-
+-        //two terms specified, check if first is a language
+-        QString customLanguage;
+-        if (terms.count() == 2) {
+-            customLanguage = terms[0];
+-            query = terms[1];
+-        }
+-        //three terms specified, check if first two are a language, e.g. "american english"
+-        if (terms.count() == 3) {
+-            customLanguage = terms[0] + ' ' + terms[1];
+-            query = terms[2];
+-        }
+-
+-        if (!customLanguage.isEmpty()) {
+-            language = customLanguage;
+-            m_speller.setLanguage(language);
++    }
+ 
+-            //not valid, maybe it is a language name, not a code
+-            if (!m_speller.isValid()) {
+-                QHash<QString, QString>::const_iterator it = m_languages.constFind(language.toLower());
+-                //is a valid language name
+-                if (it != m_languages.constEnd()) {
+-                    language = *it;
++    //Pointer to speller object with our chosen language
++    QSharedPointer<Sonnet::Speller> speller = m_spellers[""];
++
++    if (speller->isValid()) {
++        QStringList terms = query.split(' ', QString::SkipEmptyParts);
++        QString lang = findlang(terms);
++        //If we found a language, create a new speller object using it.
++        if (!lang.isEmpty()) {
++            //First term is the language
++            terms.removeFirst();
++            //New speller object if we don't already have one
++            if (!m_spellers.contains(lang)) {
++                QMutexLocker lock (&m_spellLock);
++                //Check nothing happened while we were acquiring the lock
++                if (!m_spellers.contains(lang)) {
++                    m_spellers[lang] = QSharedPointer<Sonnet::Speller>(new Sonnet::Speller(lang));
+                 }
+             }
++            speller = m_spellers[lang];
++            //Rejoin the strings
++            query = terms.join(QLatin1String(" "));
+         }
+-
+-        m_speller.setLanguage(language);
+     }
+ 
+-    if (query.size() < 3) {
++    if (query.size() < 2) {
+         return;
+     }
+ 
+     Plasma::QueryMatch match(this);
+     match.setType(Plasma::QueryMatch::InformationalMatch);
+ 
+-    if (m_speller.isValid()) {
++    if (speller->isValid()) {
+         QStringList suggestions;
+-        const bool correct = m_speller.checkAndSuggest(query,suggestions);
++        const bool correct = speller->checkAndSuggest(query,suggestions);
+         if (correct) {
+             match.setIcon(KIcon(QLatin1String( "checkbox" )));
+-            match.setText(i18n("Correct"));
++            match.setText(i18n("Correct")+QLatin1String(": ")+query);
+         } else {
+             match.setIcon(KIcon(QLatin1String( "edit-delete" )));
+             const QString recommended = i18n("Suggested words: %1", suggestions.join(i18nc("seperator for a list of words", ", ")));
+diff --git a/runners/spellchecker/spellcheck.h b/runners/spellchecker/spellcheck.h
+index 492c370..ca65452 100644
+--- a/runners/spellchecker/spellcheck.h
++++ b/runners/spellchecker/spellcheck.h
+@@ -22,6 +22,7 @@
+ #include <sonnet/speller.h>
+ 
+ #include <plasma/abstractrunner.h>
++#include <QSharedPointer>
+ 
+ /**
+  * This checks the spelling of query
+@@ -41,12 +42,17 @@ public:
+ 
+ protected slots:
+     void init();
++    void loaddata();
++    void destroydata();
+ 
+ private:
++    QString findlang(const QStringList &terms);
++
+     QString m_triggerWord;
+-    QHash<QString, QString> m_languages;//key=language name, value=language code
++    QMap<QString, QString> m_languages;//key=language name, value=language code
+     bool m_requireTriggerWord;
+-    Sonnet::Speller m_speller;
++    QMap<QString, QSharedPointer<Sonnet::Speller> > m_spellers; //spellers
++    QMutex m_spellLock; //Lock held when constructing a new speller
+ };
+ 
+ K_EXPORT_PLASMA_RUNNER(spellcheckrunner, SpellCheckRunner)




More information about the arch-commits mailing list