-
Notifications
You must be signed in to change notification settings - Fork 0
/
YamlNavigator.py
70 lines (56 loc) · 1.98 KB
/
YamlNavigator.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
import sublime, sublime_plugin, yaml, re
class YamlNavigatorCommand(sublime_plugin.WindowCommand):
def run(self):
view = self.window.active_view()
if view:
text = view.substr(sublime.Region(0, view.size()))
self.line_detector = LineDetector(text)
self.window.show_input_panel("Yaml Selector:", "", None, self.on_change, None)
pass
def on_change(self, query):
view = self.window.active_view()
if query and view:
line = self.line_detector.line_num(query) + 1
view.run_command("goto_line", {"line": line})
class Node(object):
def __init__(self, name, line, parent):
self.name = name
self.line = line
self.parent = parent
class LineDetector(object):
def __init__(self, text):
self.nodes = self.build_graph(text)
def build_graph(self, text):
events = yaml.parse(text)
node_stack = [None]
nodes = []
mapping_changed = False
for event in events:
if type(event) is yaml.MappingStartEvent:
mapping_changed = True
else:
if type(event) is yaml.MappingEndEvent:
mapping_changed = True
node_stack.pop()
else:
if type(event) is yaml.ScalarEvent:
if mapping_changed:
node = Node(event.value, event.start_mark.line, node_stack[-1])
nodes.append(node)
node_stack.append(node)
mapping_changed = not mapping_changed
return nodes
def line_num(self, query):
def node_matches_selectors(node, selectors):
if not selectors: return True
if not node: return False
new_selectors = selectors[:-1] if re.search(selectors[-1], node.name) else selectors
return node_matches_selectors(node.parent, new_selectors)
query_parts = query.split()
first_selector = query_parts.pop()
line = 0
for node in self.nodes:
if re.search(first_selector, node.name) and node_matches_selectors(node.parent, query_parts):
line = node.line
break
return line