From 98ec4b8f2e34de26d98fa116814b2333a81d6716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Alvari=C3=B1o?= Date: Wed, 12 Jan 2022 12:43:10 +0100 Subject: [PATCH] First basic functional version --- README.md | 5 +++ mach5 | 8 +++++ machlib/menu.py | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 2 ++ 4 files changed, 102 insertions(+) create mode 100755 mach5 create mode 100644 machlib/menu.py create mode 100644 requirements.txt diff --git a/README.md b/README.md index 8db4b1f..01d703f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ # Mach5 A chords app for Linux + + +## TODO + +- More checks on command contructor diff --git a/mach5 b/mach5 new file mode 100755 index 0000000..2cf0f37 --- /dev/null +++ b/mach5 @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +from machlib.menu import Menu, get_data_from + +# import subprocess +# from getkey import getkey, keys + +Menu(get_data_from('~/.config/mach5/menu.yml')).get_command().execute() diff --git a/machlib/menu.py b/machlib/menu.py new file mode 100644 index 0000000..ca55dbf --- /dev/null +++ b/machlib/menu.py @@ -0,0 +1,87 @@ +"""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) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..db57203 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +PyYAML==6.0 +getkey==0.6.5