import sublime, sublime_plugin

class SelectQuotedStringInclCommand(sublime_plugin.TextCommand):
	STATE_UNKNOWN = -1
	STATE_NOT_ESCAPED = 0
	STATE_ESCAPED = 1

	def expand_selection(self, sel):
		# Get cursor position
		idx = sel.begin () - 1

		# Search for double and single quotes
		quotes = ["'", '"']
		quote = False
		while (quote == False) and (idx >= 0):
			char = self.view.substr (idx)
			if char in quotes:
				if idx == 0:
					# First character in file cannot be escaped
					quote = char
					first = idx
				else:
					# Found one, but make sure it is not escaped with a backslash (taking into account escaped backslashed)
					tmp = idx - 1
					status = self.STATE_UNKNOWN
					count = 0
					while (status == self.STATE_UNKNOWN) and (tmp >= 0):
						prev = self.view.substr (tmp)
						if prev == '\\':
							++count
						else:
							if count & 1:
								status = self.STATE_ESCAPED
							else:
								status = self.STATE_NOT_ESCAPED
						tmp = tmp - 1
					if status == self.STATE_NOT_ESCAPED:
						quote = char
						first = idx
					else:
						idx = tmp + 1
			else:
				idx -= 1
		
		# Quote has been found, so look for the end of the string terminated by that same quote
		if quote != False:
			# Cannot start at cursor position, as it may be inside an escape sequence
			idx = first + 1
			while (char != '\0'):
				char = self.view.substr (idx)
				if (char == quote):
					# All done, give back the expanded selection
					return sublime.Region (first, idx + 1)
				else:
					if (char == '\\'):
						idx += 2
					else:
						idx += 1

		# No quote found or end of string was reached
		return False


	def run(self, edit):
		# Prepare a list of current selections and new selections
		current_selections = self.view.sel ()
		new_selections = []

		# Expand each selection
		for sel in current_selections:
			expanded = self.expand_selection (sel)
			if expanded != False:
				# If it is a valid selection, add it to the range
				new_selections.append (expanded)

		# If there are suffient selections, adjust
		if len (new_selections) > 0:
			self.view.sel ().clear ()
			for sel in new_selections:
				self.view.sel ().add (sel)
			return True

		# No valid selection
		return False
