Add remote control of slide deck

This commit is contained in:
Jerome Petazzoni
2017-12-21 05:29:59 +01:00
parent 718031565e
commit 720989e829

View File

@@ -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)