Sublime Forum

[Added] API request: view.unfold([regions])

#1

I would like to request an API function for view.unfold([regions]).

It seems for fold we have view.fold(region) and view.fold([regions]), but for unfold we only have view.unfold(region) which is very slow if you have large lists of regions to unfold; it can even cause hanging.

I found this issue when playing with the RegReplace function in a large file. It was able to fold all the comments in the file based on a scope select very fast, but was very, very, very (had to task kill sublimetext) slow in the reverse due to the looping and calling the unfold command over and over. It would be nice if we could just send in a list of regions and have sublimetext do it in native code.

0 Likes

#2

+1 (and view.folded_regions([regions]))

In the meantime you can use view.unfold(sublime.Region(0, view.size())), though that will of course nuke ALL the folds.

So the trick is to just unfold everything and refold the areas you care about.

So if you wanted to unfold comment regions, you’d store the existing regions returned by view.unfold, subtract the comments somehow, then refold.

There’s no builtin RegionSet functionality like subtract available apart from view.sel() so you can either rewrite RegionSet in Python or temporarily set view.sel() to the result of view.unfold to perform calculations.

I think if any region passed to view.unfold intersects a folded region, the entire region will be unfolded, rather than it being subtractive.

Most likely you’d only want to remove an existing folded region if it was of exactly the same size as a comment region. You wouldn’t want to show just the comment of a folded out function yeah? Likewise you wouldn’t want to unfold a whole function when unfolding comments. So the semantics of view.sel().subtract and view.unfold respectively aren’t likely what you are looking for.

Unfortunately the __hash__ function on sublime.Region seems to return the same hash for different regions:

[code]>>> hash(sublime.Region(0, 0))
101618048

hash(sublime.Region(10, 20))
101618048[/code]

If I’m not mistaken, if this wasn’t the case you could just make a set() of regions from the view.unfold list and then subtract the comment region set() relatively efficiently.

0 Likes

#3

I am looking into getting getting all regions and comparing them to see how long that would take. If it doesn’t take too long, then clearing all folded regions and refolding the ones not of interest wouldn’t be too bad. If it is too resource intensive, I will just set an unfold threshold: if threshold is exceeded, forget about preserving and just unfold everything. Ideally I won’t have to do this, but we shall see. In this one case, I was literally folding and unfolding 7000 regions. It was one ginormous script.

view.unfold([regions]) sure would be great. Then I wouldn’t have to go around the butt to get to the elbow. :smile:

0 Likes

#4

[code]def tupled_set(regions):
return set((r.a, r.b) for r in regions)

def subtract_exacts(a, b):
a_map = dict(((r.a, r.b) , r) for r in a)
return a_map[t] for t in (set(a_map) - tupled_set(b)) ]
[/code]

I wouldn’t imagine you would get too much faster than that. Dicts, tuples and list comprehensions are pretty fast/efficient.

You could use a hash() of the tuple for keys if you were concerned with memory but you’d get collisions after a point.

The only issue is now it’s in a random order. Though your are likely passing the results directly to view.fold at this point.

It seems faster (when subtracting 50k regions etc :smile:) than even doing the following, where you are instantiating new Region objects:

def subtract_exacts_new_regions(a, b): return sublime.Region(*t) for t in (tupled_set(a) - tupled_set(b)) ]

I had a play and it’s also faster than the bisect based method I cooked up.

0 Likes

#5

[quote=“castles_made_of_sand”][code]def tupled_set(regions):
return set((r.a, r.b) for r in regions)

def subtract_exacts(a, b):
a_map = dict(((r.a, r.b) , r) for r in a)
return a_map[t] for t in (set(a_map) - tupled_set(b)) ]
[/code]
I had a play and it’s also faster than the bisect based method I cooked up.[/quote]

Nice; very clever! :smile:

I am in the process of doing some bench testing with it. I let you know how it does.

0 Likes

#6

Sweet :smile:

If you get a nice bisect based one I’d love to see / learn from it.

0 Likes

#7

Might have to do r.begin(), r.end() to normalise selection directions eh?

0 Likes

#8

Yeah, I did.

So I started out by folding all comments, and then I did a regex to fold each alpha-numeric character individually. It was like 16,000 folds. :smile:


It was able to sort out all 16,000 and leave the comments folded. Granted, I am on a faster computer here than I was at work. I am going to wait to test the same scenario that was feezing me up, but your algorithm worked very nice here at home.

I’ll let you know if I get a fast bisect one going, but I think this is more than fast enough. Though the challenge to get faster is always fun too. :smile:

0 Likes

#9

haha madness :smile:

0 Likes

#10

I showed up to work and tried it out on the file that brought ST2 to a halt, and it had no problem unfolding the regions quite quickly. I tried a bunch of stuff, but it looks like your algorithm is a winner. It made it tougher too, once you see one way of doing things, it is tough to un-see, and not gravitate back to it.

Thanks for the help. This really makes the “unfold” option viable again.

Though a view.unfold([regions]) would still be great! :wink:

0 Likes

#11

I guess when there’s a specific metric, namely speed in this case, there’ll be convergent thinking.

There was a saying amongst the Python core devs, “We study Knuth, so you don’t have to”

It’s cool what you can do in Python with just an addled, fuzzy appromimation of understanding.

I wouldn’t even know where to start in implementing a hash table in Python let alone C :smile:

0 Likes

#12

en.wikipedia.org/wiki/Hash_table

Interestering.

0 Likes