Sublime Forum

ExpandSelectionToScope

#1

Hello All,

I have been working on a command that selects words matching your current selection in the current scope (based on braces). Basically like super+d but grabs everything in scope at once.

Currently,
It selects matches to the nearest pair of braces {}
It includes a for/if/foreach/function/class line preceding the {, since that almost always makes sense.
If all the matches are already selected, it selects to the next containing pair of braces.
It looks for whole words, because in practice for me that has seemed better, but that would probably make a good config option.
Relies on the langage grammer for the file to ignore braces in comments and strings.
It doesn’t really understand any language scope rules, just goes off of a generalized c-like assumption about braces.
It doesn’t understand scope in braceless languages (python), but does select all matches in the file.

I’m new to python, and to sublime, so I was thinking I would post this here to see if anyone had any suggestions on how to improve the code (specifically on style, but also suggestion for features are welcome). Also, if people think this would be useful to others, I’d be happy to share and to open source it. Where would be the most appropriate place to post this code so others can find it?

Thank you

import sublime, sublime_plugin
import re

class ExtendSelectionToScopeCommand(sublime_plugin.TextCommand):
	def scopeStart(self, brace_pos):
		return not self.view.substr(brace_pos) == "}"

	def run(self, edit):
		#print "Extend Selection To Scope"
		if self.view.sel()[0].a == self.view.sel()[0].b:
			sel = self.view.sel()
			sel.add(self.view.word(sel[0].a));                    
			return

		pos = self.view.sel()[0].a
		word = self.view.substr(self.view.sel()[0]);
		

		# FIND SCOPE DELIMS
		regex_parts = ];
		regex_parts.append("((class|function)^\;]*?\{)");
		regex_parts.append("((if|while|foreach)^\;]*?\{)"); 
		regex_parts.append("(for.*\)^\;]*?\{)"); 
		regex_parts.append("(\{)"); 
		regex_parts.append("(\})"); 
		regex = "|".join(regex_parts);
		scope_delims = self.view.find_all(regex)

		clean_scope_delims = ]
		for match in scope_delims:
			if (not self.view.match_selector(match.a, "(string|comment)")):
				clean_scope_delims.append(match)
		scope_delims = clean_scope_delims

		

		# FIND SURROUNDING SCOPES
		surrounding_scopes = ]
		scope_stack = ]
		for scope_delim in scope_delims:
			brace_pos = scope_delim.a	
			if self.scopeStart(brace_pos):
				scope_stack.append(sublime.Region(brace_pos, brace_pos))							
			elif len(scope_stack) > 0:
				scope_stack-1] = sublime.Region(scope_stack-1].a, brace_pos)
				if scope_stack-1].a < pos and scope_stack-1].b >= pos:
					surrounding_scopes.append(scope_stack-1])
				scope_stack.pop()
		
		surrounding_scopes.append((sublime.Region(0, self.view.size())))
		
		

		#FIND MATCHES
		matching_words = self.view.find_all("\W"+re.escape(word)+"\W")
		for index in range(0, len(matching_words)):
			matching_words[index] = sublime.Region(matching_words[index].a+1, matching_words[index].b-1)

		
		
		#SELECT MATCHES
		surrounding_scopes.reverse()
		sel = self.view.sel()
		extended = False
		while extended == False and len(surrounding_scopes) > 0:
			target_scope = surrounding_scopes.pop()
			for matching_word in matching_words:
				if matching_word.a >= target_scope.a and matching_word.b <= target_scope.b:
					if not sel.contains(matching_word):
						extended = True
					sel.add(matching_word)
0 Likes