mirror of
https://github.com/jpetazzo/container.training.git
synced 2026-07-15 19:09:43 +00:00
Add remote control of slide deck
This commit is contained in:
@@ -43,9 +43,6 @@ class State(object):
|
||||
next_step=self.next_step), f, default_flow_style=False)
|
||||
|
||||
|
||||
state = State()
|
||||
|
||||
|
||||
def hrule():
|
||||
return "="*int(subprocess.check_output(["tput", "cols"]))
|
||||
|
||||
@@ -99,6 +96,54 @@ class Slide(object):
|
||||
def debug(self):
|
||||
logging.debug("\n{}\n{}\n{}".format(hrule(), self.content, hrule()))
|
||||
|
||||
# Synchronize slides in a remote browser
|
||||
class Remote(object):
|
||||
|
||||
def __init__(self):
|
||||
self.slide_on_screen = 0
|
||||
|
||||
# Directly go to a specific slide
|
||||
def goto(self, slide_number):
|
||||
subprocess.check_call(["./gotoslide.js", str(slide_number)])
|
||||
self.slide_on_screen = slide_number
|
||||
focus_slides()
|
||||
|
||||
# Offer the opportunity to go step by step to the given slide
|
||||
def catchup(self, slide_number):
|
||||
if self.slide_on_screen > slide_number:
|
||||
return self.goto(slide_number)
|
||||
while self.slide_on_screen < slide_number:
|
||||
if state.interactive:
|
||||
print("Catching up on slide: {} -> {}"
|
||||
.format(self.slide_on_screen, slide_number))
|
||||
print("z Zoom to target slide")
|
||||
print("n/➡️/⎵ Next slide")
|
||||
print("p/⬅️ Previous slide")
|
||||
command = click.getchar()
|
||||
else:
|
||||
command = "z"
|
||||
if command == "z":
|
||||
self.goto(slide_number)
|
||||
elif command in ("n", "\x1b[C", " "):
|
||||
self.goto(self.slide_on_screen+1)
|
||||
elif command in ("p", "\x1b[D"):
|
||||
self.goto(self.slide_on_screen-1)
|
||||
|
||||
|
||||
def focus_slides():
|
||||
subprocess.check_call(["i3-msg", "workspace", "3"])
|
||||
subprocess.check_call(["i3-msg", "workspace", "1"])
|
||||
time.sleep(1)
|
||||
|
||||
def focus_terminal():
|
||||
subprocess.check_call(["i3-msg", "workspace", "2"])
|
||||
subprocess.check_call(["i3-msg", "workspace", "1"])
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
remote = Remote()
|
||||
state = State()
|
||||
|
||||
|
||||
def ansi(code):
|
||||
return lambda s: "\x1b[{}m{}\x1b[0m".format(code, s)
|
||||
@@ -171,7 +216,20 @@ def setup_tmux_and_ssh():
|
||||
|
||||
slides = []
|
||||
content = open(sys.argv[1]).read()
|
||||
|
||||
# OK, this part is definitely hackish, and will break if the
|
||||
# excludedClasses parameter is not on a single line.
|
||||
excluded_classes = re.findall("excludedClasses: (\[.*\])", content)
|
||||
excluded_classes = set(eval(excluded_classes[0]))
|
||||
|
||||
for slide in re.split("\n---?\n", content):
|
||||
slide_classes = re.findall("class: (.*)", slide)
|
||||
if slide_classes:
|
||||
slide_classes = slide_classes[0].split(",")
|
||||
slide_classes = [c.strip() for c in slide_classes]
|
||||
if excluded_classes & set(slide_classes):
|
||||
logging.info("Skipping excluded slide.")
|
||||
continue
|
||||
slides.append(Slide(slide))
|
||||
|
||||
actions = []
|
||||
@@ -225,17 +283,20 @@ while state.next_step < len(actions):
|
||||
# Remove extra spaces (we don't want them in the terminal) and carriage returns
|
||||
data = data.strip()
|
||||
|
||||
# Synchronize the remote slides
|
||||
remote.catchup(slide.number)
|
||||
|
||||
print(hrule())
|
||||
print(slide.content.replace(snippet.content, ansi(7)(snippet.content)))
|
||||
print(hrule())
|
||||
if state.interactive:
|
||||
print("simulate_type:{} verify_status:{}".format(state.simulate_type, state.verify_status))
|
||||
print("[{}/{}] Shall we execute that snippet above?".format(state.next_step, len(actions)))
|
||||
print("y/⏎/→ Execute snippet")
|
||||
print("y/⏎ Execute snippet")
|
||||
print("p/← Previous snippet")
|
||||
print("s Skip snippet")
|
||||
print("t Toggle typist simulation")
|
||||
print("v Toggle verification of exit status")
|
||||
print("n/→ Next snippet")
|
||||
print("s Simulate keystrokes")
|
||||
print("v Validate exit status")
|
||||
print("g Go to a specific snippet")
|
||||
print("q Quit")
|
||||
print("c Continue non-interactively until next error")
|
||||
@@ -249,11 +310,11 @@ while state.next_step < len(actions):
|
||||
logging.info("Stripping ` from snippet.")
|
||||
data = data.replace('`', '')
|
||||
|
||||
if command == "s":
|
||||
if command in ("n", "\x1b[C"):
|
||||
state.next_step += 1
|
||||
elif command in ("p", "\x1b[D"):
|
||||
state.next_step -= 1
|
||||
elif command == "t":
|
||||
elif command == "s":
|
||||
state.simulate_type = not state.simulate_type
|
||||
elif command == "v":
|
||||
state.verify_status = not state.verify_status
|
||||
@@ -264,7 +325,8 @@ while state.next_step < len(actions):
|
||||
elif command == "c":
|
||||
# continue until next timeout
|
||||
state.interactive = False
|
||||
elif command in ("y", "\r", " ", "\x1b[C"):
|
||||
elif command in ("y", "\r", " "):
|
||||
focus_terminal()
|
||||
logging.info("Running with method {}: {}".format(method, data))
|
||||
if method == "keys":
|
||||
send_keys(data)
|
||||
|
||||
Reference in New Issue
Block a user