forked from aronwoost/sublime-expand-region
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexpand_to_symbols.py
136 lines (110 loc) · 4.01 KB
/
expand_to_symbols.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import re
try:
import utils
except:
from . import utils
def expand_to_symbols(string, selection_start, selection_end):
opening_symbols = "([{";
closing_symbols = ")]}";
symbols_regex = re.compile("[" + re.escape(opening_symbols + closing_symbols)+"]")
quotes_regex = re.compile("(['\"])(?:\\1|.*?\\1)")
quotes_blacklist = {}
# get all quoted strings and create dict with key of index = True
# Example: f+"oob"+bar
# quotes_blacklist = {
# 2: true, 3: true, 4: true, 5: true, 6: true
# }
for match in quotes_regex.finditer(string):
quotes_start = match.start()
quotes_end = match.end()
i = 0;
while True:
quotes_blacklist[quotes_start + i] = True
i += 1
if (quotes_start + i == quotes_end):
break;
counterparts = {
"(":")",
"{":"}",
"[":"]",
")":"(",
"}":"{",
"]":"["
}
# find symbols in selection that are "not closed"
selection_string = string[selection_start:selection_end]
selection_quotes = symbols_regex.findall(selection_string)
backward_symbols_stack = []
forward_symbols_stack = []
if(len(selection_quotes) != 0):
inspect_index = 0
# remove symbols that have a counterpart, i.e. that are "closed"
while True:
item = selection_quotes[inspect_index]
if(counterparts[item] in selection_quotes):
del selection_quotes[selection_quotes.index(item)]
del selection_quotes[selection_quotes.index(counterparts[item])]
else:
inspect_index = inspect_index + 1
if(inspect_index >= len(selection_quotes)):
break;
# put the remaining "open" symbols in the stack lists depending if they are
# opening or closing symbols
for item in selection_quotes:
if(item in opening_symbols):
forward_symbols_stack.append(item)
elif(item in closing_symbols):
backward_symbols_stack.append(item)
search_index = selection_start - 1;
# look back from begin of selection
while True:
# begin of string reached
if(search_index < 0):
return None
# skip if current index is within a quote
if (quotes_blacklist.get(search_index, False) == True):
search_index -= 1
continue;
character = string[search_index:search_index + 1]
result = symbols_regex.match(character)
if result:
symbol = result.group()
# symbol is opening symbol and stack is empty, we found the symbol we want to expand to
if(symbol in opening_symbols and len(backward_symbols_stack) == 0):
symbols_start = search_index + 1
break
if len(backward_symbols_stack) > 0 and backward_symbols_stack[len(backward_symbols_stack) - 1] == counterparts[symbol]:
# last symbol in the stack is the counterpart of the found one
backward_symbols_stack.pop()
else:
backward_symbols_stack.append(symbol)
search_index -= 1
symbol_pair_regex = re.compile("[" + re.escape(symbol + counterparts[symbol]) + "]")
forward_symbols_stack.append(symbol)
search_index = selection_end;
# look forward from end of selection
while True:
# skip if current index is within a quote
if (quotes_blacklist.get(search_index, False) == True):
search_index += 1
continue;
character = string[search_index:search_index + 1]
result = symbol_pair_regex.match(character)
if result:
symbol = result.group()
if forward_symbols_stack[len(forward_symbols_stack) - 1] == counterparts[symbol]:
# counterpart of found symbol is the last one in stack, remove it
forward_symbols_stack.pop()
else:
forward_symbols_stack.append(symbol)
if len(forward_symbols_stack) == 0:
symbols_end = search_index;
break
# end of string reached
if search_index == len(string):
return
search_index += 1
if(selection_start == symbols_start and selection_end == symbols_end):
return utils.create_return_obj(symbols_start - 1, symbols_end + 1, string, "symbol")
else:
return utils.create_return_obj(symbols_start, symbols_end, string, "symbol")