Home Download Buy Blog Forum Support

Split/iterate [regions]

Split/iterate [regions]

Postby agibsonsw on Sat Oct 06, 2012 11:53 pm

I'm using add_regions to add hidden regions to a view. I then want to extract elements from this [region], but I receive the error "Region 'object' is not iterable".

Code: Select all
edited = self.view.get_regions("edited_rgns") or []
a, b = edited[-1]


Is there a way that I can coerce [region] into a standard list of tuples pl?
"I'm here to save your life. But if I'm going to do that, I'll need total uninanonynymity." Me Myself & Irene.
agibsonsw
 
Posts: 901
Joined: Fri Jan 27, 2012 9:11 pm

Re: Split/iterate [regions]

Postby facelessuser on Sun Oct 07, 2012 6:51 am

import sublime
import sublime_plugin

sublime.Region.totuple = lambda self: (self.a, self.b)
sublime.Region.__iter__ = lambda self: self.totuple().__iter__()


class TupleRegionCommand(sublime_plugin.TextCommand):
def run(self, edit):
regions = self.view.get_regions("bh_round") or []
if len(regions):
a, b = regions[-1]
print a, b




See what I did there ;). With this, every region has a method to get its tuple form, but if you want to iterate the Region, you have now provided the python iterator requirement.
facelessuser
 
Posts: 1549
Joined: Tue Apr 05, 2011 7:38 pm

Re: Split/iterate [regions]

Postby sublimator on Sun Oct 07, 2012 7:05 am

Except someone else patched Region.__iter__ to return an xrange(r.begin(), r.end()) and all was hell in the world :/

IMO, you wanna avoid monkey patches unless really needed
It is better to remain silent and be thought a fool, than to speak out and remove all doubt
sublimator
 
Posts: 649
Joined: Thu Mar 20, 2008 5:41 am

Re: Split/iterate [regions]

Postby agibsonsw on Sun Oct 07, 2012 11:51 am

Thank you @facelessuser

Code: Select all
Except someone else patched Region.__iter__ to return an xrange(r.begin(), r.end()) and all was hell in the world :/

IMO, you wanna avoid monkey patches unless really needed

I agree, and it turns out I may not need to - but it's nice to know that I can if necessary :).

Continuing this topic slightly, how can I create a RegionSet? It seems it is only possible via sel() or add_regions?
"I'm here to save your life. But if I'm going to do that, I'll need total uninanonynymity." Me Myself & Irene.
agibsonsw
 
Posts: 901
Joined: Fri Jan 27, 2012 9:11 pm

Re: Split/iterate [regions]

Postby sublimator on Sun Oct 07, 2012 1:18 pm

Yeah, monkey patching is seductively cool and there are legitimate uses for it, however that doesn't seem to be one. I've written heaps of plugins I can't share cause I used a heap of monkey patches.

You can't actually instantiate a RegionSet, only get a reference to one via view.sel(). You can make a crappy implementation in Python though.

import bisect
import sublime

def subtract_region(r1, r2):
if not r1.contains(r2): r2 = r1.intersection(r2)

r1s, r1e
= r1.begin(), r1.end()
r2s, r2e
= r2.begin(), r2.end()

if r1s == r2s and r1e == r2e:
return []
elif r1s == r2s:
return [sublime.Region(r2e, r1e)]
elif r1e == r2e:
return [sublime.Region(r1s, r2s)]
else:
return [sublime.Region(r1s, r2s), sublime.Region(r2e, r1e)]

class PyRegionSet(list):
def __init__(self, l=[], merge=False):
if merge:
list.__init__(self)
for r in l: self.add(l)
else:
list.__init__(self, l)

def bisect(self, r):
ix
= min(bisect.bisect(self, r), len(self) -1)
reg
= self[ix]
if r < reg and not (reg.contains(r) or reg.intersects(r)): ix -= 1
return max(0, ix)

def clear(self):
del self[:]

def contains(self, r):
return self and self.closest_selection(r).contains(r)

def closest_selection(self, r):
return self[self.bisect(r)]

def add(self, r):
if not self: return self.append(r)

for ix in xrange(self.bisect(r), -1, -1):
closest
= self[ix]

if closest.contains(r) or closest.intersects(r):
self[ix] = closest.cover(r)
return

elif r.contains(closest) or r.intersects(closest):
r
= r.cover(closest)
if ix: del self[ix]
else: self[ix] = r
else:
self.insert(ix+1, r)
return

def subtract(self, r):
ix
= self.bisect(r)

while self:
closest
= self[ix]

if closest.contains(r) or closest.intersects(r):
del self[ix]
for reg in subtract_region(closest, r):
bisect.insort(
self, reg)

if ix == len(self): break
continue
break
It is better to remain silent and be thought a fool, than to speak out and remove all doubt
sublimator
 
Posts: 649
Joined: Thu Mar 20, 2008 5:41 am

Re: Split/iterate [regions]

Postby facelessuser on Sun Oct 07, 2012 1:22 pm

castles_made_of_sand wrote:Except someone else patched Region.__iter__ to return an xrange(r.begin(), r.end()) and all was hell in the world :/

IMO, you wanna avoid monkey patches unless really needed


:) yeah, yeah. It is the same argument made with not prototyping things like array etc in javascript (which is a completely valid argument). It all depends how isolated your code will be, but yeah, if you are going to be communicating with other plugins, then you might have a problem. If you are only talking directly with the API, then you are probably okay. But the same logic could just be contained in a regular function totuplelist that you feed a RegionSet or list of Regions.

agibsonsw wrote:Thank you @facelessuser

Code: Select all
Except someone else patched Region.__iter__ to return an xrange(r.begin(), r.end()) and all was hell in the world :/

IMO, you wanna avoid monkey patches unless really needed

I agree, and it turns out I may not need to - but it's nice to know that I can if necessary :).

Continuing this topic slightly, how can I create a RegionSet? It seems it is only possible via sel() or add_regions?


You pretty much answered your own question. It cannot be instantiated from Python. It is Jon's custom class which he hasen't really given access to. The easiest way is to bug Jon...or not use it except when accessing set() and add_regions().
Last edited by facelessuser on Sun Oct 07, 2012 1:28 pm, edited 1 time in total.
facelessuser
 
Posts: 1549
Joined: Tue Apr 05, 2011 7:38 pm

Re: Split/iterate [regions]

Postby facelessuser on Sun Oct 07, 2012 1:27 pm

Yeah, monkey patching is seductively cool and there are legitimate uses for it, however that doesn't seem to be one. I've written heaps of plugins I can't share cause I used a heap of monkey patches.

You can't actually instantiate a RegionSet, only get a reference to one via view.sel(). You can make a crappy implementation in Python though.


There is that too. As long as the API functions don't really check the types of what you send in, you could use something like that, but if they do, you would then have to convert your PyRegionSet back to a list of of Regions...unless you are only using it for convenience in your code.
facelessuser
 
Posts: 1549
Joined: Tue Apr 05, 2011 7:38 pm

Re: Split/iterate [regions]

Postby sublimator on Sun Oct 07, 2012 1:29 pm

>>> not prototyping things like array

Are you talking about JavaScript extending of prototypes?

>>> if you are going to be communicating with other plugins, then you might have a problem

?
It is better to remain silent and be thought a fool, than to speak out and remove all doubt
sublimator
 
Posts: 649
Joined: Thu Mar 20, 2008 5:41 am

Re: Split/iterate [regions]

Postby sublimator on Sun Oct 07, 2012 1:33 pm

>>> As long as the API functions don't really check the types of what you send in, you could use something like that

Code: Select all
>>> rs = PyRegionSet(list(view.sel()))
>>> view.add_regions('derpa', rs, '')
>>> view.get_regions('derpa')
[(2131, 2131)]
It is better to remain silent and be thought a fool, than to speak out and remove all doubt
sublimator
 
Posts: 649
Joined: Thu Mar 20, 2008 5:41 am

Re: Split/iterate [regions]

Postby sublimator on Sun Oct 07, 2012 1:35 pm

>>> Are you talking about JavaScript extending of prototypes?

NM, I missed the part where you said JavaScript.
It is better to remain silent and be thought a fool, than to speak out and remove all doubt
sublimator
 
Posts: 649
Joined: Thu Mar 20, 2008 5:41 am

Next

Return to Technical Support

Who is online

Users browsing this forum: Google [Bot] and 11 guests