"""Implements Mach5 menues.""" import os.path import errno import yaml from collections import OrderedDict from getkey import getkey, keys import subprocess def get_data_from(menu_file): """Get menu data from a yaml menu file.""" menu_file = os.path.expanduser(menu_file) if not os.path.exists(menu_file): raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), menu_file) with open(menu_file, 'r') as yaml_file: menu_data = yaml.safe_load(yaml_file) if 'entries' not in menu_data: raise ValueError(f"Malformed file {menu_file}.\ First entry is not a menu") return(menu_data) class Command: """A Mach5 command.""" def __init__(self, cmd_data): """Construct a Mach5 command object.""" if len(cmd_data['sc']) != 1: raise ValueError(f"Shortcut must be only one character.\ {cmd_data['heu']} is invalid.") self._name = cmd_data['name'] self._cmd = cmd_data['cmd'] self._sc = cmd_data['sc'] def show(self): """Return string for Command.""" return f"{self._sc} - {self._name}" def execute(self): """Execute command.""" subprocess.Popen(os.path.expanduser(self._cmd)) class Menu: """A Mach5 menu.""" def __init__(self, menu_data): """Construct a menu object from a menu data dict.""" self._name = menu_data['name'] self._entries = OrderedDict() self._sc = menu_data['sc'] for e in menu_data['entries']: if e['sc'] in self._entries: raise ValueError(f"Repeated shortcut {e['sc']}") if 'entries' in e: self._entries[e['sc']] = Menu(e) else: self._entries[e['sc']] = Command(e) def show(self, recursive=False): """Show Menu.""" my_str = "" if self._sc: my_str = f"{self._sc} - " my_str += f"{self._name} (m)" if recursive: my_str += "\n" for i, v in self._entries.items(): my_str += f"{v.show()}\n" return my_str def get_command(self): """Get command from menu.""" print(self.show(True)) while True: opt = getkey() if opt in self._entries: if isinstance(self._entries[opt], Menu): return self._entries[opt].get_command() else: return self._entries[opt] elif opt == keys.ESC: exit(0)