koehlma / pygtkspellcheck

A simple but quite powerful spellchecking library for GTK written in pure Python.
GNU General Public License v3.0
23 stars 9 forks source link

Get's horrible slow at ~50.000 chars #11

Closed wolfv closed 12 years ago

wolfv commented 12 years ago

Hey,

everything works great unless you try to use pygtkspellcheck on a document of average size. I mean, 50.000 chars is not extremely much.

Rightclicking takes ~4-5 seconds, while the application remains completely unresponsive.

My guess is that spellcheck runs completely over the document everytime after a rightclick was initiated. Just thought I'd let you know.

wolfv
koehlma commented 12 years ago

Hi,

hmmm, I can say it shouldn't run over the whole document everytime. I think it would be really interesting to know in which part of the program this waste of time happens.

How does Gedit handle these files? As I know they are using the same algorithm (the one from gtkspell) - maybe this is just because of Python...

Greetings Maxi

wolfv commented 12 years ago

I guess i found what looks like the bug:

    item.connect('activate', _set_language, code)
    if code == self.language:
        item.set_active(True)

which causes the entire buffer to be «rechecked» which in turn causes quite some overhead, since one already has red strokes under wrong words :)

wolfv commented 12 years ago

Oh well, the source is here: https://github.com/koehlma/pygtkspellcheck/blob/master/src/gtkspellcheck/spellcheck.py#L392

wolfv commented 12 years ago

So i have looked a little closer and found that the "activate" get's fired with the first entry after initializing (for me its de_AT). So it changes language to de_AT where it should stay being en_US.

After the for loop "reaches" en_US it fires activate again.

That leads to 2 times checking all of the text in the textview, only for opening the right-click-popup menu.

I might fire up a fix tonight ...

wolfv commented 12 years ago

I'm appending my fix here as I am not sure wether it will work with the old GTK or not:

    def _languages_menu(self):
        def _set_language(item, code):
            if self._language != code:
                self._language = code

        if _pygobject:
            menu = gtk.Menu.new()
            group = []
        else:
            menu = gtk.Menu()
            group = gtk.RadioMenuItem()
        for code, name in self.languages:
            if _pygobject:
                item = gtk.RadioMenuItem.new_with_label(group, name)
                group.append(item)
            else:
                item = gtk.RadioMenuItem(group, name)

            if code == self._language:
                item.set_active(True)

            menu.append(item)

        if _pygobject:
            for item in group:
                item.connect('activate', _set_language, code)
        else:
            for item in menu:
                item.connect('activate', _set_language, code)

        return menu

and

    @language.setter
    def language(self, language):
        if self.languages.exists(language):
            if self._language != language:
                self._language = language
                self._dictionary = self._broker.request_dict(language)
                self.recheck()
wolfv commented 12 years ago

Oh, the setter is'nt working properly anymore, maybe one of you guys can fix it better :)

koehlma commented 12 years ago

Hi,

thanks for this great analyses and the code, should be fixed now.

The only problem with your code was that the language code would be the same for every item in this case:

    for item in group:
        item.connect('activate', _set_language, code)

Greetings Maxi