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
158
159
160
161
162
163
164
|
"""An interactive front-end for Triplet Structures.
Call from runtime.py:interactive(...).
"""
# pylint: disable=import-error,no-name-in-module
from runtime.shadow_input import ShadowInput
class TSREPL:
"""An interactive interface for the TSRuntime.
"""
def __init__(self, runtime):
"""Initializes a new TSREPL.
"""
self.runtime = runtime
self.ts = runtime.ts
self.input = ShadowInput()
def run(self):
"""Run the REPL.
"""
while True:
if self.iteration() == "EXIT":
return
def iteration(self):
"""Prompt the user for an action and execute it.
"""
print("Starting a new iteration. Please pick an option:")
option = self.select_one([
"Manually apply individual rules.",
"Automatically apply all rules matching pattern.",
"Print structure.",
"Begin recording command sequence.",
"Save command sequence.",
"Load command sequence.",
"Set display name.",
"Prefer nodes.",
"Exit interactive session.",
])
if option == 0:
self.apply_manual()
elif option == 1:
self.to_fixedpoint()
elif option == 2:
print(self.ts)
elif option == 3:
self.input.begin_recording()
elif option == 4:
file_name = self.input("Save to file: ")
self.input.scrub_last(2)
self.input.save_recording(file_name)
elif option == 5:
file_name = self.input("Load from file: ")
self.input.load_recording(file_name)
elif option == 6:
self.set_display_name()
elif option == 7:
self.prefer_nodes()
elif option == 8:
return "EXIT"
else:
raise NotImplementedError
return None
def to_fixedpoint(self):
"""Apply rule(s) until fixedpoint is reached.
"""
rules = self.pick_rules()
search_term = self.input("Search proposals for term: ").lower()
n_matches = int(self.input("Apply if at least this many matches: "))
fixedpoint = False
while not fixedpoint:
fixedpoint = True
for _, delta in self.runtime.propose_all(rules):
if str(delta).lower().count(search_term) >= n_matches:
print("Applying proposal:")
print(delta)
delta.apply()
fixedpoint = False
break
def apply_manual(self):
"""Manually apply rule(s).
"""
rules = self.pick_rules()
search_term = self.input("Filter proposals for term: ").lower()
n_matches = int(self.input("With at least this many matches: ") or "0")
while True:
for _, delta in self.runtime.propose_all(rules):
if str(delta).lower().count(search_term) < n_matches:
continue
print(delta)
choice = self.input("Apply? (y/N/q): ").lower() or "n"
if choice[0] == "y":
delta.apply()
break
if choice[0] == "q":
return
else:
return
def set_display_name(self):
"""Allows the user to set a display name for a particular node.
"""
search_term = self.input("Existing display name: ")
matching = [
node for node, display_name in self.ts.display_names.items()
if search_term in display_name]
if matching:
node_name = min(
matching, key=lambda node: len(self.ts.display_names[node]))
new_name = self.input("Please select a new display name: ")
self.ts[node_name].display_name(new_name)
else:
print("No matching node.")
def prefer_nodes(self):
"""Tell the runtime to prefer particular nodes in matches.
"""
search_term = self.input("Prefer nodes containing string: ")
self.runtime.affinity.prefer_nodes(lambda node: search_term in node)
def pick_rules(self):
"""Helper to allow the user to select rules to apply.
"""
names = [rule.name for rule in self.runtime.rules]
print("Please select the rule(s):")
indices = self.select_multiple(names)
return [names[i] for i in indices]
def select_one(self, options):
"""Helper method for selecting an option.
"""
for i, option in enumerate(options):
print("{}: {}".format(i, option))
index = self.input("Selection: ").lower()
try:
option = options[int(index)]
return int(index)
except (ValueError, IndexError):
try:
# Treat it as a search term
return next(i for i, option in enumerate(options)
if index in str(option).lower())
except StopIteration:
print("Invalid choice, try again.")
return self.select_one(options)
def select_multiple(self, options):
"""Helper method for selecting multiple options.
"""
for i, option in enumerate(options):
print("{}: {}".format(i, option))
term = self.input("Selections: ").lower()
try:
if "-" in term:
from_index, to_index = map(int, term.split("-")[:2])
else:
from_index, to_index = int(term), int(term)
return list(range(from_index, to_index + 1))
except ValueError:
return [i for i, option in enumerate(options)
if term in str(option).lower()]
|