From 3c5d00ac3db8ddfbdccdb37f78476cc64645185d Mon Sep 17 00:00:00 2001 From: Griatch Date: Wed, 28 Mar 2018 23:56:23 +0200 Subject: [PATCH] Almost working list_node evmenu decorator --- evennia/utils/evmenu.py | 105 +++++++++++++++++++++++---------------- evennia/utils/spawner.py | 15 +++++- 2 files changed, 76 insertions(+), 44 deletions(-) diff --git a/evennia/utils/evmenu.py b/evennia/utils/evmenu.py index 148ba4c0dc..6c8729aee1 100644 --- a/evennia/utils/evmenu.py +++ b/evennia/utils/evmenu.py @@ -1002,61 +1002,82 @@ def list_node(option_list, examine_processor, goto_processor, pagesize=10): """ - def _rerouter(caller, raw_string): - "Parse which input was given, select from option_list" - - caller.ndb._menutree - - goto_processor - - - def decorator(func): - all_options = [{"desc": opt, "goto": _rerouter} for opt in option_list] - all_options = list(sorted(all_options, key=lambda d: d["desc"])) + def _input_parser(caller, raw_string, **kwargs): + "Parse which input was given, select from option_list" - nall_options = len(all_options) - pages = [all_options[ind:ind + pagesize] for ind in range(0, nall_options, pagesize)] + available_choices = kwargs.get("available_choices", []) + processor = kwargs.get("selection_processor") + try: + match_ind = int(re.search(r"[0-9]+$", raw_string).group()) - 1 + selection = available_choices[match_ind] + except (AttributeError, KeyError, IndexError, ValueError): + return None + + if processor: + try: + return processor(caller, selection) + except Exception: + logger.log_trace() + return selection + + nall_options = len(option_list) + pages = [option_list[ind:ind + pagesize] for ind in range(0, nall_options, pagesize)] npages = len(pages) - def _examine_select(caller, raw_string, **kwargs): - - match = re.search(r"[0-9]+$", raw_string) - - - page_index = kwargs.get("optionpage_index", 0) - - def _list_node(caller, raw_string, **kwargs): - # update text with detail, if set - - - # dynamic, multi-page option list page_index = max(0, min(npages - 1, kwargs.get("optionpage_index", 0))) + page = pages[page_index] - options = pages[page_index] + # dynamic, multi-page option list. We use _input_parser as a goto-callable, + # with the `goto_processor` redirecting when we leave the node. + options = [{"desc": opt, + "goto": (_input_parser, + {"available_choices": page, + "selection_processor": goto_processor})} for opt in page] - if options: - if npages > 1: - # if the goto callable returns None, the same node is rerun, and - # kwargs not used by the callable are passed on to the node. - if page_index > 0: - options.append({"desc": "prev", - "goto": (lambda caller: None, - {"optionpage_index": page_index - 1})}) - if page_index < npages - 1: - options.append({"desc": "next", - "goto": (lambda caller: None, - {"optionpage_index": page_index + 1})}) - options.append({"key": "_default", - "goto": (_examine_select, {"optionpage_index": page_index})}) + if npages > 1: + # if the goto callable returns None, the same node is rerun, and + # kwargs not used by the callable are passed on to the node. This + # allows us to call ourselves over and over, using different kwargs. + if page_index > 0: + options.append({"key": ("|wb|Wack|n", "b"), + "goto": (lambda caller: None, + {"optionpage_index": page_index - 1})}) + if page_index < npages - 1: + options.append({"key": ("|wn|Wext|n", "n"), + "goto": (lambda caller: None, + {"optionpage_index": page_index + 1})}) + + options.append({"key": ("|Wcurrent|n", "c"), + "desc": "|W({}/{})|n".format(page_index + 1, npages), + "goto": (lambda caller: None, + {"optionpage_index": page_index})}) + options.append({"key": "_default", + "goto": (lambda caller: None, + {"show_detail": True, "optionpage_index": page_index})}) + + # update text with detail, if set. Here we call _input_parser like a normal function + text_detail = None + if raw_string and 'show_detail' in kwargs: + text_detail = _input_parser( + caller, raw_string, **{"available_choices": page, + "selection_processor": examine_processor}) + if text_detail is None: + text_detail = "|rThat's not a valid command or option.|n" # add data from the decorated node + text = '' try: text, extra_options = func(caller, raw_string) + except TypeError: + try: + text, extra_options = func(caller) + except Exception: + raise except Exception: logger.log_trace() else: @@ -1066,14 +1087,14 @@ def list_node(option_list, examine_processor, goto_processor, pagesize=10): extra_options = make_iter(extra_options) options.append(extra_options) + text = text + "\n\n" + text_detail if text_detail else text + return text, options return _list_node return decorator - - # ------------------------------------------------------------------------------------------------- # # Simple input shortcuts diff --git a/evennia/utils/spawner.py b/evennia/utils/spawner.py index 25298476c6..3b2d6d4353 100644 --- a/evennia/utils/spawner.py +++ b/evennia/utils/spawner.py @@ -109,13 +109,14 @@ from django.conf import settings from random import randint import evennia from evennia.objects.models import ObjectDB -from evennia.utils.utils import make_iter, all_from_module, dbid_to_obj, is_iter, crop +from evennia.utils.utils import ( + make_iter, all_from_module, dbid_to_obj, is_iter, crop, get_all_typeclasses) from collections import namedtuple from evennia.scripts.scripts import DefaultScript from evennia.utils.create import create_script from evennia.utils.evtable import EvTable -from evennia.utils.evmenu import EvMenu +from evennia.utils.evmenu import EvMenu, list_node _CREATE_OBJECT_KWARGS = ("key", "location", "home", "destination") @@ -856,6 +857,16 @@ def node_prototype(caller): return text, options +def _typeclass_examine(caller, typeclass): + return "This is typeclass |y{}|n.".format(typeclass) + + +def _typeclass_select(caller, typeclass): + caller.msg("Selected typeclass |y{}|n.".format(typeclass)) + return None + + +@list_node(list(sorted(get_all_typeclasses().keys())), _typeclass_examine, _typeclass_select) def node_typeclass(caller): metaprot = _get_menu_metaprot(caller) prot = metaprot.prototype