diff --git a/patch2vimedit/main.py b/patch2vimedit/main.py new file mode 100644 index 0000000..6746bba --- /dev/null +++ b/patch2vimedit/main.py @@ -0,0 +1,74 @@ +import argparse +import pathlib +import os +import sys +import time + +import patch +from tmux import TmuxSession + + +def parse_args(): + """ Parse command-line arguments """ + parser = argparse.ArgumentParser(prog="patch2vimedit") + parser.add_argument( + "-C", + "--directory", + metavar="DIR", + help="Change to DIR before performing any operations.", + ) + parser.add_argument( + "patch", + help=( + "The patch file to be applied. If '-' is supplied, reads from STDIN " + "instead." + ), + ) + return parser.parse_args() + + +def get_patch(patch_path): + if patch_path == "-": + return patch.PatchSet(sys.stdin) + with open(patch_path, "rb") as stream: + return patch.PatchSet(stream) + + +def main(): + """ Entry-point function """ + args = parse_args() + + if args.directory: + chdir_to = pathlib.Path(args.directory) + if not chdir_to.is_dir(): + print( + ( + "The required working directory '{}' does not exist, or is not a " + "directory." + ).format(str(chdir_to)), + file=sys.stderr, + ) + sys.exit(1) + os.chdir(chdir_to) + + patchset = get_patch(args.patch) + + tmux_session = TmuxSession.create_detached() + tmux_fg_process = tmux_session.process_attach(read_only=True) + + time.sleep(0.2) + tmux_session.send_keys('echo "Hello, world!"', "enter") + time.sleep(1) + tmux_session.send_keys('echo "Bye, world!"', "enter") + time.sleep(1) + tmux_session.send_keys("exit", "enter") + + tmux_fg_process.join(1) + if tmux_fg_process.exitcode is None: # Did not terminate -- kill it + tmux_fg_process.kill() + if tmux_session.session_exists(): + tmux_session.session.kill_session() + + +if __name__ == "__main__": + main() diff --git a/patch2vimedit/tmux.py b/patch2vimedit/tmux.py new file mode 100644 index 0000000..85bd76b --- /dev/null +++ b/patch2vimedit/tmux.py @@ -0,0 +1,59 @@ +import subprocess +import multiprocessing +import sys +import random +import libtmux + + +class TmuxSession: + """ A tmux session """ + + tmux_server = libtmux.Server() + + def __init__(self, session): + self.session = session + self.session_id = session.id + + @classmethod + def create_detached(cls, name=None): + """ Create a new detached tmux session, returning the TmuxSession """ + if not name: + name = "patch2vimsession-{:04x}".format(random.randint(0, 1 << 16 - 1)) + session = cls.tmux_server.new_session(session_name=name, attach=False) + return cls(session) + + def attach(self): + """ Attach the tmux session to the current terminal. Does NOT return until the + tmux session ends or is detached. """ + self.session.attach_session() + + def attach_ro(self): + """ Same as `attach`, but attaches a tmux session in a read-only fashion (see + `tmux attach -r`). """ + # libtmux is not expressive enough to avoid `subprocess` here... + subprocess.run(["tmux", "attach", "-r", "-t", self.session.id], check=True) + + def session_exists(self): + """ Checks that the session exists """ + return self.tmux_server.has_session(self.session_id) + + def process_attach(self, read_only=True): + """ Runs `self.attach` in a `multiprocessing.Process` and returns the process. + """ + target = self.attach_ro if read_only else self.attach + process = multiprocessing.Process(target=target) + process.start() + return process + + def send_keys(self, *args): + """ Send keys to the tmux process. See `man tmux` and `tmux send-keys` for + documentation """ + for arg in args: + self.session.attached_pane.send_keys( + arg, suppress_history=False, enter=False + ) + + +# subprocess.run( +# ["tmux", "send-keys", "-t", self.session.id] + list(args), check=True +# ) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f458a1e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +patch==1.* +libtmux==0.8.*