Sublime Forum

Slow performance of my autonbsp plugin

#1

Hello. I am working on my own module which will replace whitespaces to   for my language. I am close to end, but now i noticed that if/when I work with long text, my SublimeText got freeze for few minutes.
I never work with python before and i don’t know, how Python works. So i think that my plugin is bad and problem with performance is problem with my code. I upload that file on Github
https://github.com/rybarova/autonbsp/blob/master/nbsp.py

It’s a good way type all regexps to new lines? Or is better to have one big regexp? My goal is that create similar converter like is that in PSPad or like here in JavaScript solution http://kod.djpw.cz/avxc

Thank you everyone who have time to help me with my bad code.

0 Likes

#2

most of your regex patterns are 99% similar, so it seems worth optimizing it as much as possible to avoid duplication…

did you try instead of:

            self.view.replace(edit,region,re.sub('(?![^<]*>)(?<=([\s\<\>\.,;&\(\)\/]a))\s', r'&nbsp;',view.substr(region),flags=re.IGNORECASE))
            self.view.replace(edit,region,re.sub('(?![^<]*>)(?<=([\s\<\>\.,;&\(\)\/]i))\s', r'&nbsp;',view.substr(region),flags=re.IGNORECASE))
            self.view.replace(edit,region,re.sub('(?![^<]*>)(?<=([\s\<\>\.,;&\(\)\/]o))\s', r'&nbsp;',view.substr(region),flags=re.IGNORECASE))
            self.view.replace(edit,region,re.sub('(?![^<]*>)(?<=([\s\<\>\.,;&\(\)\/]u))\s', r'&nbsp;',view.substr(region),flags=re.IGNORECASE))
            self.view.replace(edit,region,re.sub('(?![^<]*>)(?<=([\s\<\>\.,;&\(\)\/]k))\s', r'&nbsp;',view.substr(region),flags=re.IGNORECASE))
            self.view.replace(edit,region,re.sub('(?![^<]*>)(?<=([\s\<\>\.,;&\(\)\/]s))\s', r'&nbsp;',view.substr(region),flags=re.IGNORECASE))
            self.view.replace(edit,region,re.sub('(?![^<]*>)(?<=([\s\<\>\.,;&\(\)\/]v))\s', r'&nbsp;',view.substr(region),flags=re.IGNORECASE))
            self.view.replace(edit,region,re.sub('(?![^<]*>)(?<=([\s\<\>\.,;&\(\)\/]z))\s', r'&nbsp;',view.substr(region),flags=re.IGNORECASE))

using a char class:

self.view.replace(edit,region,re.sub('(?![^<]*>)(?<=([\s\<\>\.,;&\(\)\/][aiouksvz]))\s', r'&nbsp;',view.substr(region),flags=re.IGNORECASE))

it doesn’t make the regex bigger - in fact it makes it smaller.

1 Like

#3

Thank you for your help and your time. What is better solution for next optimalisation:

1 ) example

 self.view.replace(edit,region,re.sub('(?![^<]*>)(?<=([\s\<\>\.,;&\(\)\/]by))\s', r'&nbsp;',view.substr(region),flags=re.IGNORECASE))
 self.view.replace(edit,region,re.sub('(?![^<]*>)(?<=([\s\<\>\.,;&\(\)\/]co))\s', r'&nbsp;',view.substr(region),flags=re.IGNORECASE))

OR

2 ) example

self.view.replace(edit,region,re.sub('(?![^<]*>)(?<=([\s\<\>\.,;&\(\)\/]by))\s|(?![^<]*>)(?<=([\s\<\>\.,;&\(\)\/]co))\s', r'&nbsp;',view.substr(region),flags=re.IGNORECASE))

Example 2 is not so much code but also not so much clearly organized. Does that have some impact for performance?

BTW: now my code works on only if I mark text. Is a possible to set, that to apply my code to all document if i have nothing marked? That will be good for faster debug my package.

0 Likes

#4

for region in [sublime.Region(0, view.size())] if all(sel.empty() for sel in view.sel()) else view.sel(): instead of just for region in view.sel() should do the trick :slight_smile:

you should just be able to use an alternation on the only part that changes, i.e.:

self.view.replace(edit,region,re.sub('(?![^<]*>)(?<=([\s\<\>\.,;&\(\)\/](?:by|co)))\s', r'&nbsp;',view.substr(region),flags=re.IGNORECASE))
3 Likes

#5

Thank you for your time and help. I can use that your last solution only when my Lookbehind have same number of characters (fixed length) or is here some solution or Flag how to do with nonfixed lenght? Or is only One solution, that I must to make another regex pattern?

Example:
(?![^<]*>)(?<=([\s\<\>\.,;&\(\)\/](?:by|co|pak|ale)))\s

0 Likes

#6

There are a couple of possibilities here:

  • use the ST API for regex searches instead of the Python re module
  • use a different Python regex module
  • look for every location without the part which changes, and search the buffer manually at each result to see if it is one you are interested in
1 Like

#7

Sorry for stupid questions. I am not user of python so i don’t understand of that. I don’t get that that how to implement other python module or how to use the ST API.
If I understand correctly I must change in only that part re.sub So for example if I want to try a regex library, must replace re to regex and that’s all? Or I must install the new library into Sublimetext or into my computer?

self.view.replace(edit,region,regex.sub('A', r'B',view.substr(region),flags=re.IGNORECASE))

and solution with ST API is similar?

self.view.replace(edit,region,find('A', r'B',view.substr(region),flags=re.IGNORECASE))


Can have some of these solutions better impact on performance? ST API will be probably faster, or…?

0 Likes

#8

well the ST API supports variable-size lookbehind IIRC. These are just suggestions to try, but obviously the less time you repeat your searches, the less time it should take to complete.

0 Likes

#9

Thank you, for your time. Variable lookbehind will be nice. Can you show me some example of the ST API on my example?

self.view.replace(edit,region,re.sub('A', r'B',view.substr(region),flags=re.IGNORECASE))

0 Likes

#10

note for ST3, the correct API documentation page is http://www.sublimetext.com/docs/3/api_reference.html

I apologize, I was wrong about variable-width lookbehind being supported by the ST find/find_all API. But you can rework it using \K to not require it I think:

        regex = r'(?<=[\s<>.,;&()/])(?![^<]*>)(?:[aiouksvz]|by|co|pak|ale)\K\s'
        regions = self.view.find_all(regex, sublime.IGNORECASE)
        for region in reversed(regions):
            self.view.replace(edit, region, '&nbsp;')

try that with all your desired replacements and measure the performance :slight_smile:

0 Likes