sublime_text icon indicating copy to clipboard operation
sublime_text copied to clipboard

The builtin `join_lines` command is too slow.

Open absop opened this issue 4 years ago • 6 comments

Description

The builtin join_lines is too slow.

import re
import sublime_plugin


class ReJoinLinesCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        selections = list(self.view.sel())
        for selection in reversed(selections):
            content = self.view.substr(selection)
            new_str = re.sub(r'\n\s*', ' ', content)
            self.view.replace(edit, selection, new_str)

The re_join_lines command provided above is a simple version of join_lines. For joining lines of non empty selection regions, its functionality is not exactly the same as join_lines, but roughly the same. For a 700-line code selection, it is 1000 times faster than join_lines, this is very strange.

>>> timeit.timeit(lambda:view.run_command('re_join_lines'), number=1)
0.005591699999058619
>>> timeit.timeit(lambda:view.run_command('join_lines'), number=1)
5.893734800001766

Environment

  • Build: 4116
  • Operating system and version: Windows 10

absop avatar Oct 03 '21 03:10 absop

I believe that the original join_lines command is implemented natively as I couldn't find it in the Default package.

Which is an issue because we don't know how much of the original functionality is your version missing. One thing missing for sure is ability to join lines with empty selection - that doesn't work with your version.

rchl avatar Oct 03 '21 19:10 rchl

There is also some "smart" functionality missing from the original which makes it either add or not add white space when joining lines. For example when joining:

[
  1,
  2,
  3
]

would produce:

[1, 2, 3 ]

which is still not ideal due to the trailing space but still better than adding space for each item.

rchl avatar Oct 03 '21 19:10 rchl

I believe that the original join_lines command is implemented natively as I couldn't find it in the Default package.

Which is an issue because we don't know how much of the original functionality is your version missing. One thing missing for sure is ability to join lines with empty selection - that doesn't work with your version.

Yes, my version is too simple, it dose not work in empty selections, misses handling for multiple selections in a single line. But the number 1000 is too large. As far as I know, VSC has no such problem.

absop avatar Oct 03 '21 19:10 absop

For a 700-line code selection, it is 1000 times faster than join_lines

Can you share this code?

rwols avatar Oct 03 '21 19:10 rwols

This kind of code is everywhere. You can select a region of hundreds of lines of code and try it out. I believe that you'll notice a noticeable lag.

@rwols

absop avatar Oct 03 '21 19:10 absop

The undo operation to the join_lines command is also costly.

>>> timeit.timeit(lambda:view.run_command('join_lines'), number=1)
5.900341100001242
>>> timeit.timeit(lambda:view.run_command('undo'), number=1)
5.82682449999993
>>> timeit.timeit(lambda:view.run_command('re_join_lines'), number=1)
0.005585900002188282
>>> timeit.timeit(lambda:view.run_command('undo'), number=1)
0.014367700001457706

absop avatar Oct 03 '21 19:10 absop