Skip to content

Instantly share code, notes, and snippets.

@TimelessP
Last active August 7, 2022 07:41
Show Gist options
  • Save TimelessP/8d45006bab00ec634a474bf3453f1772 to your computer and use it in GitHub Desktop.
Save TimelessP/8d45006bab00ec634a474bf3453f1772 to your computer and use it in GitHub Desktop.
In my side quest to find a concise and fun way to create menus, I have now created minimalmenu3.py
#!/usr/bin/env python3
"""
minimalmenu3.py by @TimelessP.
MIT Licence.
2022-08-04
https://gist.github.com/TimelessP/8d45006bab00ec634a474bf3453f1772
"""
import os
import subprocess
from enum import Enum
class Actions(Enum):
FUNCTION = 1
EXIT = 2
MENU = 3
SHELL_COMMAND = 4
class Menu:
def __init__(self, menu_data):
self.menu_data = menu_data
self._choice = None
self._menu_title = None
def run(self):
while True:
self._print_menu()
self._get_input()
if self._choice and self._choice.get(Actions.EXIT, None):
# If it's callable, call it first, then break out the loop.
if callable(self._choice[Actions.EXIT]):
self._choice[Actions.EXIT]()
break
self._process_input()
def _print_menu(self):
# Print the current menu.
self._menu_title = list(self.menu_data.keys())[0]
print(os.linesep + self._menu_title + os.linesep + "-" * len(self._menu_title))
# Print the menu items.
for index, option in enumerate(self.menu_data[self._menu_title], start=1):
print(f"{index}. {option['option']}")
def _get_input(self):
try:
self._choice = None
# The user inputs the choice number, and we store the selected option in self.choice.
choice_number = input("? ")
# Validate the choice.
if choice_number.isdigit():
choice_number = int(choice_number)
if choice_number in range(1, len(self.menu_data[self._menu_title]) + 1):
# Store the selected option as the choice.
self._choice = self.menu_data[self._menu_title][choice_number - 1]
else:
print("Invalid choice.")
self._choice = None
else:
print("Invalid choice.")
except (KeyboardInterrupt, EOFError):
return
def _process_input(self):
# Process the input.
if self._choice:
if self._choice.get(Actions.FUNCTION, None):
# Call the function.
self._choice[Actions.FUNCTION]()
elif self._choice.get(Actions.MENU, None):
# Change the current menu.
next_menu = self._choice.get(Actions.MENU)
# If next_menu is a str then eval() the string.
if isinstance(next_menu, str):
next_menu = eval(next_menu)
self.menu_data = next_menu
elif self._choice.get(Actions.SHELL_COMMAND, None):
# Run a shell command and print the return code.
print(f"Return code: {subprocess.call(self._choice[Actions.SHELL_COMMAND], shell=True)}")
self._choice = None
def print_hello():
print("Hello World")
def print_goodbye():
print("Goodbye World")
exit(0)
if __name__ == '__main__':
sub_menu = {
"Sub Menu": [
{"option": "Print hello", Actions.FUNCTION: print_hello},
{"option": "Main Menu", Actions.MENU: 'main_menu'},
]
}
main_menu = {
"Main Menu": [
{"option": "Print hello", Actions.FUNCTION: print_hello},
{"option": "Sub menu", Actions.MENU: sub_menu},
{"option": "Lambda test", Actions.FUNCTION: lambda: print("Lambda test")},
{"option": "Directory listing", Actions.SHELL_COMMAND: "ls || dir"},
{"option": "Exit", Actions.EXIT: print_goodbye},
]
}
Menu(main_menu).run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment