-
Notifications
You must be signed in to change notification settings - Fork 14
/
expression.py
157 lines (133 loc) · 4.62 KB
/
expression.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import re
import sublime
import FuzzyFilePath.common.settings as settings
import FuzzyFilePath.common.selection as Selection
import FuzzyFilePath.common.verbose as logger
ID = "Expression"
NEEDLE_SEPARATOR = ">\"\'\(\)\{\}"
NEEDLE_SEPARATOR_BEFORE = "\"\'\(\{"
NEEDLE_SEPARATOR_AFTER = "^\"\'\)\}"
NEEDLE_CHARACTERS = "\.A-Za-z0-9\-\_$"
NEEDLE_INVALID_CHARACTERS = "\"\'\)=\:\(<>\n\{\}"
DELIMITER = "\s\:\(\[\=\{"
def get_context(view):
error = False
valid = True
valid_needle = True
position = Selection.get_position(view)
# regions
word_region = view.word(position)
line_region = view.line(position)
pre_region = sublime.Region(line_region.a, word_region.a)
post_region = sublime.Region(word_region.b, line_region.b)
# text
line = view.substr(line_region)
word = view.substr(word_region)
pre = view.substr(pre_region)
post = view.substr(post_region)
error = re.search("[" + NEEDLE_INVALID_CHARACTERS + "]", word)
needle_region = view.word(position)
# grab everything in 'separators'
needle = ""
separator = False
pre_match = ""
# search for a separator before current word, i.e. <">path/to/<position>
pre_quotes = re.search("(["+NEEDLE_SEPARATOR_BEFORE+"])([^"+NEEDLE_SEPARATOR+"]*)$", pre)
if pre_quotes:
needle += pre_quotes.group(2) + word
separator = pre_quotes.group(1)
pre_match = pre_quotes.group(2)
needle_region.a -= len(pre_quotes.group(2))
else:
# use whitespace as separator
pre_quotes = re.search("(\s)([^"+NEEDLE_SEPARATOR+"\s]*)$", pre)
if pre_quotes:
needle = pre_quotes.group(2) + word
separator = pre_quotes.group(1)
pre_match = pre_quotes.group(2)
needle_region.a -= len(pre_quotes.group(2))
if pre_quotes:
post_quotes = re.search("^(["+NEEDLE_SEPARATOR_AFTER+"]*)", post)
if post_quotes:
needle += post_quotes.group(1)
needle_region.b += len(post_quotes.group(1))
else:
logger.verbose(ID, "no post quotes found => invalid")
valid = False
elif not re.search("["+NEEDLE_INVALID_CHARACTERS+"]", needle):
needle = pre + word
needle_region.a = pre_region.a
else:
needle = word
# grab prefix
prefix_region = sublime.Region(line_region.a, pre_region.b - len(pre_match) - 1)
prefix_line = view.substr(prefix_region)
# # print("prefix line", prefix_line)
#define? (["...", "..."]) -> before?
# before: ABC =:([
prefix = re.search("\s*(["+NEEDLE_CHARACTERS+"]+)["+DELIMITER+"]*$", prefix_line)
if prefix is None:
# validate array, like define(["...", ".CURSOR."])
prefix = re.search("^\s*(["+NEEDLE_CHARACTERS+"]+)["+DELIMITER+"]+", prefix_line)
if prefix:
# print("prefix:", prefix.group(1))
prefix = prefix.group(1)
tag = re.search("<\s*(["+NEEDLE_CHARACTERS+"]*)\s*[^>]*$", prefix_line)
if tag:
tag = tag.group(1)
# print("tag:", tag)
propertyName = re.search("[\s\"\'']*(["+NEEDLE_CHARACTERS+"]*)[\s\"\']*\:[^\:]*$", prefix_line)
if propertyName:
propertyName = propertyName.group(1)
# print("style:", style)
if separator is False:
logger.verbose(ID, "separator undefined => invalid", needle)
valid_needle = False
valid = False
elif re.search("["+NEEDLE_INVALID_CHARACTERS+"]", needle):
logger.verbose(ID, "invalid characters in needle => invalid", needle)
valid_needle = False
valid = False
elif prefix is None and separator.strip() == "":
logger.verbose(ID, "prefix undefined => invalid", needle)
valid = False
return {
"is_valid": valid,
"valid_needle": valid_needle,
"needle": needle,
"prefix": prefix,
"tagName": tag,
"style": propertyName,
"region": needle_region,
"word": word,
# really do not use any of this
"error": error
}
def check_trigger(trigger, expression):
# returns True if the expression statements match the trigger
for statement in set(settings.get("trigger_statements")).intersection(trigger):
values = trigger.get(statement)
# statement values may be None (or any other value...)
if type(values) is list and not expression.get(statement) in values:
return False
# validate other value by comparison
# elif not values == expression.get(statement):
# return False
return True
def find_trigger(expression, scope, triggers):
for trigger in triggers:
# if the trigger is defined for the current scope
# REQUIRED? scope = properties.get("scope").replace("//", "")
if re.search(trigger["scope"], scope):
# validate its statements on the current context
if check_trigger(trigger, expression):
return trigger
return False
def get_rule(view):
selection = view.sel()[0]
position = selection.begin()
word_region = view.word(position)
current_scope = view.scope_name(word_region.a)
context = get_context(view)
rule = find_rule(context, current_scope)
return [rule, context] if rule else False