Sublime Forum

View.replace & view.erase bug?

#1

I don’t know if I’m missing something but the plugin from sublimator https://forum.sublimetext.com/t/set-cursor-position/187/1 reveals a strange behavior of view.replace() and view.erase().
Have a look at the comments

        for sel in view.sel():
            end_pt = sel.end()
            # if len(sel) == 0 the textposition will become bof! 
            # to prevent this insert a space
            if end_pt != view.size():
                view.insert (end_pt, ' ')

        view.runCommand ('invertSelection')
        for sel in view.sel():
            # now remove the inserted space
            print '|%s|%d' % (view.substr (sel), len (sel))    # to verify selection is just ' '
            if len (sel) == 1:
                view.replace (sel, '')  # removes too many spaces
            elif len (sel) > 1:
                view.erase (sublime.Region (sel.begin(), sel.begin()+1)) # removes too many spaces

Example (| is the cursor position, _ is a space):

  • before running the command:
    view.replace_____|(sel, ‘’)

  • after running:
    view.replace|(sel, ‘’)

  • all spaces left to | should not be replaced as len(sel) = 1 (because of the inserted space above)

  • it prints:
    | |1

View.erase behaves the same. All preceeding spaces will be erased. No tabs, real spaces.

0 Likes

#2

The behaviour you’re seeing comes from running invertSelection: Any selection containing one or more empty selection regions (the usual case) is not truly invertible, such that running invertSelection twice will generally not return you to where you started.

The attached snippet tries to work around this by inserting spaces, but fails to update the selection regions to include the spaces, so there are still empty selection regions present.

0 Likes

#3

Mea Culpa!
I was quite sure there was no bug but I didn’t realized the space at the end of the region.

Thanks sublimator and no, you’re not wasting my time!
I’m learning from your solutions. It may be a long and exciting quest.

…and the quest succeeds.
I filtered the input from sublimator and jps and changed the regex of remove_trailing. The regex know requires whitespace followed by a ‘\n’ or ‘\r’ as eol marker. Thats all on Windows and Unix files.

#! python
# -*- coding: utf-8 -*-

"""
TextCommand:
    stripSpace [preceding]
"""

import functools
import re
import textwrap

import sublime
import sublimeplugin

remove_trailing = functools.partial (re.compile (r" \t]+(\r\n])", re.M).sub, '\\1')

class StripSpaceCommand (sublimeplugin.TextCommand):

    def stripRegion (self, view, region, operation):
        view.replace (region, operation (view.substr (region)))

    def run (self, view, args):
        operation = (textwrap.dedent if 'preceding' in args else remove_trailing)
        if not view.hasNonEmptySelectionRegion():  
            view.sel().add (sublime.Region (0, view.size()))
        for region in view.sel():
            self.stripRegion (view, region, operation)

    def onPreSave (self, view):
        view.runCommand ('invertSelection')
        for sel in view.sel():
            stripped = remove_trailing(view.substr (sel))
            view.replace (sel, stripped)
        for sel in view.sel():
            end_pt = sel.end()
            # if len(sel) == 0, cursor jumps to bof, therefore...
            if end_pt !=   view.size():
                view.insert (end_pt, ' ')
        view.runCommand ('invertSelection')
        for sel in view.sel():
            if len (sel) == 1:
                view.replace (sel, '')
            elif len (sel) > 1:
                view.erase (sublime.Region (sel.begin(), sel.begin()+1))
0 Likes