Skip to content

Instantly share code, notes, and snippets.

@EgZvor
Last active July 4, 2022 12:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save EgZvor/7f346e20439420747a209e3a69096044 to your computer and use it in GitHub Desktop.
Save EgZvor/7f346e20439420747a209e3a69096044 to your computer and use it in GitHub Desktop.
A script to convert specially constructed Vim log into a lines with raw key presses.
"""See
https://hub.netzgemeinde.eu/channel/vim_sensei?mid=b64.aHR0cHM6Ly9odWIuaG90ZWxkYWFuLm5sL2l0ZW0vZGU2MjI1MDgtZjc1Ni00MGUzLWI1MTgtYjE1YTkwYTg2MWJi
for details on how to set up Vim to produce the log that this script parses.
"""
import fileinput
import os
import re
import signal
import sys
DEBUG = os.environ.get("DEBUG", False)
interrupted = False
def sigpipe_handler(_signo, _frame):
global interrupted
interrupted = True
signal.signal(signal.SIGPIPE, sigpipe_handler)
def main():
timestamp_pattern = rb"\s*\d+.\d+\s+:\s+"
# Patterns to leave out irrelevant `modes`.
enter_command_line_window = re.compile(
timestamp_pattern + rb"::Entering command-line window::"
)
enter_command_line_mode = re.compile(
timestamp_pattern + rb"::Entering command-line mode::"
)
enter_insert_mode = re.compile(timestamp_pattern + rb"::Entering Insert Mode::")
leave_command_line_window = re.compile(
timestamp_pattern + rb"::Leaving command-line window::"
)
leave_command_line_mode = re.compile(
timestamp_pattern + rb"::Leaving command-line mode::"
)
leave_insert_mode = re.compile(timestamp_pattern + rb"::Leaving Insert Mode::")
raw_key_input = re.compile(
timestamp_pattern + rb'raw key input: "(?P<key>.{,10}?)"'
)
def match_enter(line) -> bool:
return bool(
enter_command_line_window.match(line)
or enter_command_line_mode.match(line)
or enter_insert_mode.match(line)
)
def match_leave(line) -> bool:
return bool(
leave_command_line_window.match(line)
or leave_command_line_mode.match(line)
or leave_insert_mode.match(line)
)
in_ignored_block = False
lineno = 0
try:
for line in fileinput.input(mode="rb"):
if interrupted:
break
lineno += 1
line: bytes
if match_enter(line):
in_ignored_block = True
continue
if match_leave(line):
in_ignored_block = False
continue
if in_ignored_block:
continue
if (m := raw_key_input.match(line)) is not None:
if DEBUG:
print(f'{lineno} {m.group("key")}')
else:
print(repr(m.group("key"))[2:-1])
sys.stdout.flush()
except BrokenPipeError:
# Python flushes standard streams on exit; redirect remaining output
# to devnull to avoid another BrokenPipeError at shutdown
devnull = os.open(os.devnull, os.O_WRONLY)
os.dup2(devnull, sys.stdout.fileno())
sys.exit(1) # Python exits with error code 1 on EPIPE
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment