import abc
from dataclasses import dataclass
from enum import StrEnum
from pexpect import replwrap
[docs]
@dataclass
class Prompt:
"""Small wrapper for a prompt shell"""
prompt: str
continuation_prompt: str | None
[docs]
class KeyCodes(StrEnum):
"""KeyCodes determined with pexpect_getch.py script (see utils/scripts)"""
def __add__(self, other):
return str(self) + "," + str(other)
ESC = "27"
F1 = "27,79,80"
F2 = "27,79,81"
F3 = "27,79,82"
# TODO: more f-keys
DEL = "27,91,51,126"
TAB = "9"
RET = "13"
ALT = "27"
A = "97"
G = "103"
R = "114"
CTRL_C = "3"
ARROW_UP = "27,91,65"
ARROW_DOWN = "27,91,66"
ARROW_RIGHT = "27,91,67"
ARROW_LEFT = "27,91,68"
[docs]
class GenericConsoleApplication(abc.ABC):
"""Class to interact with console applications opened through a VirshConsole.
Warnings:
It is NOT intended to be used in a GUI
"""
def __init__(self, pty: replwrap.REPLWrapper, name: str):
"""Create a new generic console application.
Args:
pty: VirshConsole's pty attribute or something similar
name: name of the opened application
"""
# TODO: swap position of name and pty to make it more similar to Application class
self._virsh = pty.child # TODO: remove this attribute and use pty.child instead
self._name = name
self._pty = pty
self._parent_prompt = Prompt(self._pty.prompt, self._pty.continuation_prompt)
[docs]
def send_text(self, text: str, new_line: bool = False):
"""Send regular text to the console application, e.g. type a line in a text editor.
Args:
text: text to be sent
new_line: should a new line symbol be appended?
"""
if new_line:
self._virsh.sendline(
text
) # FIXME: This will only append the hosts line seperator
else:
self._virsh.send(text)
[docs]
def send_key_combination(self, key_combination: KeyCodes | str):
"""Send a key combination to the console.
Multiple KeyCodes might be chained with '+'
Args:
key_combination: one or more KeyCodes to be sent
"""
eval_str = ""
for key in key_combination.split(","):
eval_str += f"chr({key}) + "
eval_str = eval_str[: len(eval_str) - 3] # strip tailing ' + ' from string
self._virsh.send(eval(eval_str)) # TODO: is eval necessary here?
[docs]
@abc.abstractmethod
def close(self):
"""Close a console application.
Call this method to return to the command line. Sometimes it might be necessary to clean the buffer by calling
self._pty.run_command("clear").
Notes:
After a call to close refrain from using the object again
"""
pass
@property
def name(self):
return self._name