Merge with develop and fix merge conflicts
This commit is contained in:
commit
72f4fedcbe
148 changed files with 20005 additions and 2718 deletions
|
|
@ -43,13 +43,18 @@ command definition too) with function definitions:
|
|||
def node_with_other_name(caller, input_string):
|
||||
# code
|
||||
return text, options
|
||||
|
||||
def another_node(caller, input_string, **kwargs):
|
||||
# code
|
||||
return text, options
|
||||
```
|
||||
|
||||
Where caller is the object using the menu and input_string is the
|
||||
command entered by the user on the *previous* node (the command
|
||||
entered to get to this node). The node function code will only be
|
||||
executed once per node-visit and the system will accept nodes with
|
||||
both one or two arguments interchangeably.
|
||||
both one or two arguments interchangeably. It also accepts nodes
|
||||
that takes **kwargs.
|
||||
|
||||
The menu tree itself is available on the caller as
|
||||
`caller.ndb._menutree`. This makes it a convenient place to store
|
||||
|
|
@ -82,12 +87,14 @@ menu is immediately exited and the default "look" command is called.
|
|||
the callable. Those kwargs will also be passed into the next node if possible.
|
||||
Such a callable should return either a str or a (str, dict), where the
|
||||
string is the name of the next node to go to and the dict is the new,
|
||||
(possibly modified) kwarg to pass into the next node.
|
||||
(possibly modified) kwarg to pass into the next node. If the callable returns
|
||||
None or the empty string, the current node will be revisited.
|
||||
- `exec` (str, callable or tuple, optional): This takes the same input as `goto` above
|
||||
and runs before it. If given a node name, the node will be executed but will not
|
||||
be considered the next node. If node/callback returns str or (str, dict), these will
|
||||
replace the `goto` step (`goto` callbacks will not fire), with the string being the
|
||||
next node name and the optional dict acting as the kwargs-input for the next node.
|
||||
If an exec callable returns the empty string (only), the current node is re-run.
|
||||
|
||||
If key is not given, the option will automatically be identified by
|
||||
its number 1..N.
|
||||
|
|
@ -158,16 +165,16 @@ evennia.utils.evmenu`.
|
|||
"""
|
||||
|
||||
import random
|
||||
import inspect
|
||||
from builtins import object, range
|
||||
|
||||
from textwrap import dedent
|
||||
from inspect import isfunction, getargspec
|
||||
from django.conf import settings
|
||||
from evennia import Command, CmdSet
|
||||
from evennia.utils import logger
|
||||
from evennia.utils.evtable import EvTable
|
||||
from evennia.utils.ansi import strip_ansi
|
||||
from evennia.utils.utils import mod_import, make_iter, pad, m_len, is_iter
|
||||
from evennia.utils.utils import mod_import, make_iter, pad, to_str, m_len, is_iter, dedent, crop
|
||||
from evennia.commands import cmdhandler
|
||||
|
||||
# read from protocol NAWS later?
|
||||
|
|
@ -182,7 +189,8 @@ _CMD_NOINPUT = cmdhandler.CMD_NOINPUT
|
|||
|
||||
# i18n
|
||||
from django.utils.translation import ugettext as _
|
||||
_ERR_NOT_IMPLEMENTED = _("Menu node '{nodename}' is not implemented. Make another choice.")
|
||||
_ERR_NOT_IMPLEMENTED = _("Menu node '{nodename}' is either not implemented or "
|
||||
"caused an error. Make another choice.")
|
||||
_ERR_GENERAL = _("Error in menu node '{nodename}'.")
|
||||
_ERR_NO_OPTION_DESC = _("No description.")
|
||||
_HELP_FULL = _("Commands: <menu option>, help, quit")
|
||||
|
|
@ -315,7 +323,7 @@ class EvMenu(object):
|
|||
auto_quit=True, auto_look=True, auto_help=True,
|
||||
cmd_on_exit="look",
|
||||
persistent=False, startnode_input="", session=None,
|
||||
**kwargs):
|
||||
debug=False, **kwargs):
|
||||
"""
|
||||
Initialize the menu tree and start the caller onto the first node.
|
||||
|
||||
|
|
@ -368,7 +376,8 @@ class EvMenu(object):
|
|||
*pickle*. When the server is reloaded, the latest node shown will be completely
|
||||
re-run with the same input arguments - so be careful if you are counting
|
||||
up some persistent counter or similar - the counter may be run twice if
|
||||
reload happens on the node that does that.
|
||||
reload happens on the node that does that. Note that if `debug` is True,
|
||||
this setting is ignored and assumed to be False.
|
||||
startnode_input (str or (str, dict), optional): Send an input text to `startnode` as if
|
||||
a user input text from a fictional previous node. If including the dict, this will
|
||||
be passed as **kwargs to that node. When the server reloads,
|
||||
|
|
@ -378,6 +387,10 @@ class EvMenu(object):
|
|||
for the very first display of the first node - after that, EvMenu itself
|
||||
will keep the session updated from the command input. So a persistent
|
||||
menu will *not* be using this same session anymore after a reload.
|
||||
debug (bool, optional): If set, the 'menudebug' command will be made available
|
||||
by default in all nodes of the menu. This will print out the current state of
|
||||
the menu. Deactivate for production use! When the debug flag is active, the
|
||||
`persistent` flag is deactivated.
|
||||
|
||||
Kwargs:
|
||||
any (any): All kwargs will become initialization variables on `caller.ndb._menutree`,
|
||||
|
|
@ -401,7 +414,7 @@ class EvMenu(object):
|
|||
"""
|
||||
self._startnode = startnode
|
||||
self._menutree = self._parse_menudata(menudata)
|
||||
self._persistent = persistent
|
||||
self._persistent = persistent if not debug else False
|
||||
self._quitting = False
|
||||
|
||||
if startnode not in self._menutree:
|
||||
|
|
@ -415,6 +428,7 @@ class EvMenu(object):
|
|||
self.auto_quit = auto_quit
|
||||
self.auto_look = auto_look
|
||||
self.auto_help = auto_help
|
||||
self.debug_mode = debug
|
||||
self._session = session
|
||||
if isinstance(cmd_on_exit, str):
|
||||
# At this point menu._session will have been replaced by the
|
||||
|
|
@ -573,6 +587,7 @@ class EvMenu(object):
|
|||
except EvMenuError:
|
||||
errmsg = _ERR_GENERAL.format(nodename=callback)
|
||||
self.caller.msg(errmsg, self._session)
|
||||
logger.log_trace()
|
||||
raise
|
||||
|
||||
return ret
|
||||
|
|
@ -606,9 +621,11 @@ class EvMenu(object):
|
|||
nodetext, options = ret, None
|
||||
except KeyError:
|
||||
self.caller.msg(_ERR_NOT_IMPLEMENTED.format(nodename=nodename), session=self._session)
|
||||
logger.log_trace()
|
||||
raise EvMenuError
|
||||
except Exception:
|
||||
self.caller.msg(_ERR_GENERAL.format(nodename=nodename), session=self._session)
|
||||
logger.log_trace()
|
||||
raise
|
||||
|
||||
# store options to make them easier to test
|
||||
|
|
@ -665,45 +682,65 @@ class EvMenu(object):
|
|||
|
||||
if isinstance(ret, str):
|
||||
# only return a value if a string (a goto target), ignore all other returns
|
||||
if not ret:
|
||||
# an empty string - rerun the same node
|
||||
return self.nodename
|
||||
return ret, kwargs
|
||||
return None
|
||||
|
||||
def extract_goto_exec(self, nodename, option_dict):
|
||||
"""
|
||||
Helper: Get callables and their eventual kwargs.
|
||||
|
||||
Args:
|
||||
nodename (str): The current node name (used for error reporting).
|
||||
option_dict (dict): The seleted option's dict.
|
||||
|
||||
Returns:
|
||||
goto (str, callable or None): The goto directive in the option.
|
||||
goto_kwargs (dict): Kwargs for `goto` if the former is callable, otherwise empty.
|
||||
execute (callable or None): Executable given by the `exec` directive.
|
||||
exec_kwargs (dict): Kwargs for `execute` if it's callable, otherwise empty.
|
||||
|
||||
"""
|
||||
goto_kwargs, exec_kwargs = {}, {}
|
||||
goto, execute = option_dict.get("goto", None), option_dict.get("exec", None)
|
||||
if goto and isinstance(goto, (tuple, list)):
|
||||
if len(goto) > 1:
|
||||
goto, goto_kwargs = goto[:2] # ignore any extra arguments
|
||||
if not hasattr(goto_kwargs, "__getitem__"):
|
||||
# not a dict-like structure
|
||||
raise EvMenuError("EvMenu node {}: goto kwargs is not a dict: {}".format(
|
||||
nodename, goto_kwargs))
|
||||
else:
|
||||
goto = goto[0]
|
||||
if execute and isinstance(execute, (tuple, list)):
|
||||
if len(execute) > 1:
|
||||
execute, exec_kwargs = execute[:2] # ignore any extra arguments
|
||||
if not hasattr(exec_kwargs, "__getitem__"):
|
||||
# not a dict-like structure
|
||||
raise EvMenuError("EvMenu node {}: exec kwargs is not a dict: {}".format(
|
||||
nodename, goto_kwargs))
|
||||
else:
|
||||
execute = execute[0]
|
||||
return goto, goto_kwargs, execute, exec_kwargs
|
||||
|
||||
def goto(self, nodename, raw_string, **kwargs):
|
||||
"""
|
||||
Run a node by name, optionally dynamically generating that name first.
|
||||
|
||||
Args:
|
||||
nodename (str or callable): Name of node or a callable
|
||||
to be called as `function(caller, raw_string)` or `function(caller)`
|
||||
to return the actual goto string.
|
||||
to be called as `function(caller, raw_string, **kwargs)` or
|
||||
`function(caller, **kwargs)` to return the actual goto string or
|
||||
a ("nodename", kwargs) tuple.
|
||||
raw_string (str): The raw default string entered on the
|
||||
previous node (only used if the node accepts it as an
|
||||
argument)
|
||||
Kwargs:
|
||||
any: Extra arguments to goto callables.
|
||||
|
||||
"""
|
||||
def _extract_goto_exec(option_dict):
|
||||
"Helper: Get callables and their eventual kwargs"
|
||||
goto_kwargs, exec_kwargs = {}, {}
|
||||
goto, execute = option_dict.get("goto", None), option_dict.get("exec", None)
|
||||
if goto and isinstance(goto, (tuple, list)):
|
||||
if len(goto) > 1:
|
||||
goto, goto_kwargs = goto[:2] # ignore any extra arguments
|
||||
if not hasattr(goto_kwargs, "__getitem__"):
|
||||
# not a dict-like structure
|
||||
raise EvMenuError("EvMenu node {}: goto kwargs is not a dict: {}".format(
|
||||
nodename, goto_kwargs))
|
||||
else:
|
||||
goto = goto[0]
|
||||
if execute and isinstance(execute, (tuple, list)):
|
||||
if len(execute) > 1:
|
||||
execute, exec_kwargs = execute[:2] # ignore any extra arguments
|
||||
if not hasattr(exec_kwargs, "__getitem__"):
|
||||
# not a dict-like structure
|
||||
raise EvMenuError("EvMenu node {}: exec kwargs is not a dict: {}".format(
|
||||
nodename, goto_kwargs))
|
||||
else:
|
||||
execute = execute[0]
|
||||
return goto, goto_kwargs, execute, exec_kwargs
|
||||
|
||||
if callable(nodename):
|
||||
# run the "goto" callable, if possible
|
||||
|
|
@ -714,6 +751,9 @@ class EvMenu(object):
|
|||
raise EvMenuError(
|
||||
"{}: goto callable must return str or (str, dict)".format(inp_nodename))
|
||||
nodename, kwargs = nodename[:2]
|
||||
if not nodename:
|
||||
# no nodename return. Re-run current node
|
||||
nodename = self.nodename
|
||||
try:
|
||||
# execute the found node, make use of the returns.
|
||||
nodetext, options = self._execute_node(nodename, raw_string, **kwargs)
|
||||
|
|
@ -746,12 +786,12 @@ class EvMenu(object):
|
|||
desc = dic.get("desc", dic.get("text", None))
|
||||
if "_default" in keys:
|
||||
keys = [key for key in keys if key != "_default"]
|
||||
goto, goto_kwargs, execute, exec_kwargs = _extract_goto_exec(dic)
|
||||
goto, goto_kwargs, execute, exec_kwargs = self.extract_goto_exec(nodename, dic)
|
||||
self.default = (goto, goto_kwargs, execute, exec_kwargs)
|
||||
else:
|
||||
# use the key (only) if set, otherwise use the running number
|
||||
keys = list(make_iter(dic.get("key", str(inum + 1).strip())))
|
||||
goto, goto_kwargs, execute, exec_kwargs = _extract_goto_exec(dic)
|
||||
goto, goto_kwargs, execute, exec_kwargs = self.extract_goto_exec(nodename, dic)
|
||||
if keys:
|
||||
display_options.append((keys[0], desc))
|
||||
for key in keys:
|
||||
|
|
@ -765,7 +805,7 @@ class EvMenu(object):
|
|||
|
||||
# handle the helptext
|
||||
if helptext:
|
||||
self.helptext = helptext
|
||||
self.helptext = self.helptext_formatter(helptext)
|
||||
elif options:
|
||||
self.helptext = _HELP_FULL if self.auto_quit else _HELP_NO_QUIT
|
||||
else:
|
||||
|
|
@ -814,6 +854,51 @@ class EvMenu(object):
|
|||
if self.cmd_on_exit is not None:
|
||||
self.cmd_on_exit(self.caller, self)
|
||||
|
||||
def print_debug_info(self, arg):
|
||||
"""
|
||||
Messages the caller with the current menu state, for debug purposes.
|
||||
|
||||
Args:
|
||||
arg (str): Arg to debug instruction, either nothing, 'full' or the name
|
||||
of a property to inspect.
|
||||
|
||||
"""
|
||||
all_props = inspect.getmembers(self)
|
||||
all_methods = [name for name, _ in inspect.getmembers(self, predicate=inspect.ismethod)]
|
||||
all_builtins = [name for name, _ in inspect.getmembers(self, predicate=inspect.isbuiltin)]
|
||||
props = {prop: value for prop, value in all_props if prop not in all_methods and
|
||||
prop not in all_builtins and not prop.endswith("__")}
|
||||
|
||||
local = {key: var for key, var in locals().items()
|
||||
if key not in all_props and not key.endswith("__")}
|
||||
|
||||
if arg:
|
||||
if arg in props:
|
||||
debugtxt = " |y* {}:|n\n{}".format(arg, props[arg])
|
||||
elif arg in local:
|
||||
debugtxt = " |y* {}:|n\n{}".format(arg, local[arg])
|
||||
elif arg == 'full':
|
||||
debugtxt = ("|yMENU DEBUG full ... |n\n" + "\n".join(
|
||||
"|y *|n {}: {}".format(key, val)
|
||||
for key, val in sorted(props.items())) +
|
||||
"\n |yLOCAL VARS:|n\n" + "\n".join(
|
||||
"|y *|n {}: {}".format(key, val)
|
||||
for key, val in sorted(local.items())) +
|
||||
"\n |y... END MENU DEBUG|n")
|
||||
else:
|
||||
debugtxt = "|yUsage: menudebug full|<name of property>|n"
|
||||
else:
|
||||
debugtxt = ("|yMENU DEBUG properties ... |n\n" + "\n".join(
|
||||
"|y *|n {}: {}".format(
|
||||
key, crop(to_str(val, force_string=True), width=50))
|
||||
for key, val in sorted(props.items())) +
|
||||
"\n |yLOCAL VARS:|n\n" + "\n".join(
|
||||
"|y *|n {}: {}".format(
|
||||
key, crop(to_str(val, force_string=True), width=50))
|
||||
for key, val in sorted(local.items())) +
|
||||
"\n |y... END MENU DEBUG|n")
|
||||
self.caller.msg(debugtxt)
|
||||
|
||||
def parse_input(self, raw_string):
|
||||
"""
|
||||
Parses the incoming string from the menu user.
|
||||
|
|
@ -840,16 +925,14 @@ class EvMenu(object):
|
|||
self.display_helptext()
|
||||
elif self.auto_quit and cmd in ("quit", "q", "exit"):
|
||||
self.close_menu()
|
||||
elif self.debug_mode and cmd.startswith("menudebug"):
|
||||
self.print_debug_info(cmd[9:].strip())
|
||||
elif self.default:
|
||||
goto, goto_kwargs, execfunc, exec_kwargs = self.default
|
||||
self.run_exec_then_goto(execfunc, goto, raw_string, exec_kwargs, goto_kwargs)
|
||||
else:
|
||||
self.caller.msg(_HELP_NO_OPTION_MATCH, session=self._session)
|
||||
|
||||
if not (self.options or self.default):
|
||||
# no options - we are at the end of the menu.
|
||||
self.close_menu()
|
||||
|
||||
def display_nodetext(self):
|
||||
self.caller.msg(self.nodetext, session=self._session)
|
||||
|
||||
|
|
@ -869,7 +952,20 @@ class EvMenu(object):
|
|||
nodetext (str): The formatted node text.
|
||||
|
||||
"""
|
||||
return dedent(nodetext).strip()
|
||||
return dedent(nodetext.strip('\n'), baseline_index=0).rstrip()
|
||||
|
||||
def helptext_formatter(self, helptext):
|
||||
"""
|
||||
Format the node's help text
|
||||
|
||||
Args:
|
||||
helptext (str): The unformatted help text for the node.
|
||||
|
||||
Returns:
|
||||
helptext (str): The formatted help text.
|
||||
|
||||
"""
|
||||
return dedent(helptext.strip('\n'), baseline_index=0).rstrip()
|
||||
|
||||
def options_formatter(self, optionlist):
|
||||
"""
|
||||
|
|
@ -949,14 +1045,188 @@ class EvMenu(object):
|
|||
node (str): The formatted node to display.
|
||||
|
||||
"""
|
||||
if self._session:
|
||||
screen_width = self._session.protocol_flags.get(
|
||||
"SCREENWIDTH", {0: _MAX_TEXT_WIDTH})[0]
|
||||
else:
|
||||
screen_width = _MAX_TEXT_WIDTH
|
||||
|
||||
nodetext_width_max = max(m_len(line) for line in nodetext.split("\n"))
|
||||
options_width_max = max(m_len(line) for line in optionstext.split("\n"))
|
||||
total_width = max(options_width_max, nodetext_width_max)
|
||||
total_width = min(screen_width, max(options_width_max, nodetext_width_max))
|
||||
separator1 = "_" * total_width + "\n\n" if nodetext_width_max else ""
|
||||
separator2 = "\n" + "_" * total_width + "\n\n" if total_width else ""
|
||||
return separator1 + "|n" + nodetext + "|n" + separator2 + "|n" + optionstext
|
||||
|
||||
|
||||
# -----------------------------------------------------------
|
||||
#
|
||||
# List node (decorator turning a node into a list with
|
||||
# look/edit/add functionality for the elements)
|
||||
#
|
||||
# -----------------------------------------------------------
|
||||
|
||||
def list_node(option_generator, select=None, pagesize=10):
|
||||
"""
|
||||
Decorator for making an EvMenu node into a multi-page list node. Will add new options,
|
||||
prepending those options added in the node.
|
||||
|
||||
Args:
|
||||
option_generator (callable or list): A list of strings indicating the options, or a callable
|
||||
that is called as option_generator(caller) to produce such a list.
|
||||
select (callable or str, optional): Node to redirect a selection to. Its `**kwargs` will
|
||||
contain the `available_choices` list and `selection` will hold one of the elements in
|
||||
that list. If a callable, it will be called as select(caller, menuchoice) where
|
||||
menuchoice is the chosen option as a string. Should return the target node to goto after
|
||||
this selection (or None to repeat the list-node). Note that if this is not given, the
|
||||
decorated node must itself provide a way to continue from the node!
|
||||
pagesize (int): How many options to show per page.
|
||||
|
||||
Example:
|
||||
@list_node(['foo', 'bar'], select)
|
||||
def node_index(caller):
|
||||
text = "describing the list"
|
||||
return text, []
|
||||
|
||||
Notes:
|
||||
All normal `goto` or `exec` callables returned from the decorated nodes will, if they accept
|
||||
**kwargs, get a new kwarg 'available_choices' injected. These are the ordered list of named
|
||||
options (descs) visible on the current node page.
|
||||
|
||||
"""
|
||||
|
||||
def decorator(func):
|
||||
|
||||
def _select_parser(caller, raw_string, **kwargs):
|
||||
"""
|
||||
Parse the select action
|
||||
"""
|
||||
available_choices = kwargs.get("available_choices", [])
|
||||
|
||||
try:
|
||||
index = int(raw_string.strip()) - 1
|
||||
selection = available_choices[index]
|
||||
except Exception:
|
||||
caller.msg("|rInvalid choice.|n")
|
||||
else:
|
||||
if callable(select):
|
||||
try:
|
||||
if bool(getargspec(select).keywords):
|
||||
return select(caller, selection, available_choices=available_choices)
|
||||
else:
|
||||
return select(caller, selection)
|
||||
except Exception:
|
||||
logger.log_trace()
|
||||
elif select:
|
||||
# we assume a string was given, we inject the result into the kwargs
|
||||
# to pass on to the next node
|
||||
kwargs['selection'] = selection
|
||||
return str(select)
|
||||
# this means the previous node will be re-run with these same kwargs
|
||||
return None
|
||||
|
||||
def _list_node(caller, raw_string, **kwargs):
|
||||
|
||||
option_list = option_generator(caller) \
|
||||
if callable(option_generator) else option_generator
|
||||
|
||||
npages = 0
|
||||
page_index = 0
|
||||
page = []
|
||||
options = []
|
||||
|
||||
if option_list:
|
||||
nall_options = len(option_list)
|
||||
pages = [option_list[ind:ind + pagesize]
|
||||
for ind in range(0, nall_options, pagesize)]
|
||||
npages = len(pages)
|
||||
|
||||
page_index = max(0, min(npages - 1, kwargs.get("optionpage_index", 0)))
|
||||
page = pages[page_index]
|
||||
|
||||
text = ""
|
||||
extra_text = None
|
||||
|
||||
# dynamic, multi-page option list. Each selection leads to the `select`
|
||||
# callback being called with a result from the available choices
|
||||
options.extend([{"desc": opt,
|
||||
"goto": (_select_parser,
|
||||
{"available_choices": page})} for opt in page])
|
||||
|
||||
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.
|
||||
options.append({"key": ("|Wcurrent|n", "c"),
|
||||
"desc": "|W({}/{})|n".format(page_index + 1, npages),
|
||||
"goto": (lambda caller: None,
|
||||
{"optionpage_index": page_index})})
|
||||
if page_index > 0:
|
||||
options.append({"key": ("|wp|Wrevious page|n", "p"),
|
||||
"goto": (lambda caller: None,
|
||||
{"optionpage_index": page_index - 1})})
|
||||
if page_index < npages - 1:
|
||||
options.append({"key": ("|wn|Wext page|n", "n"),
|
||||
"goto": (lambda caller: None,
|
||||
{"optionpage_index": page_index + 1})})
|
||||
|
||||
# add data from the decorated node
|
||||
|
||||
decorated_options = []
|
||||
supports_kwargs = bool(getargspec(func).keywords)
|
||||
try:
|
||||
if supports_kwargs:
|
||||
text, decorated_options = func(caller, raw_string, **kwargs)
|
||||
else:
|
||||
text, decorated_options = func(caller, raw_string)
|
||||
except TypeError:
|
||||
try:
|
||||
if supports_kwargs:
|
||||
text, decorated_options = func(caller, **kwargs)
|
||||
else:
|
||||
text, decorated_options = func(caller)
|
||||
except Exception:
|
||||
raise
|
||||
except Exception:
|
||||
logger.log_trace()
|
||||
else:
|
||||
if isinstance(decorated_options, dict):
|
||||
decorated_options = [decorated_options]
|
||||
else:
|
||||
decorated_options = make_iter(decorated_options)
|
||||
|
||||
extra_options = []
|
||||
if isinstance(decorated_options, dict):
|
||||
decorated_options = [decorated_options]
|
||||
for eopt in decorated_options:
|
||||
cback = ("goto" in eopt and "goto") or ("exec" in eopt and "exec") or None
|
||||
if cback:
|
||||
signature = eopt[cback]
|
||||
if callable(signature):
|
||||
# callable with no kwargs defined
|
||||
eopt[cback] = (signature, {"available_choices": page})
|
||||
elif is_iter(signature):
|
||||
if len(signature) > 1 and isinstance(signature[1], dict):
|
||||
signature[1]["available_choices"] = page
|
||||
eopt[cback] = signature
|
||||
elif signature:
|
||||
# a callable alone in a tuple (i.e. no previous kwargs)
|
||||
eopt[cback] = (signature[0], {"available_choices": page})
|
||||
else:
|
||||
# malformed input.
|
||||
logger.log_err("EvMenu @list_node decorator found "
|
||||
"malformed option to decorate: {}".format(eopt))
|
||||
extra_options.append(eopt)
|
||||
|
||||
options.extend(extra_options)
|
||||
text = text + "\n\n" + extra_text if extra_text else text
|
||||
|
||||
return text, options
|
||||
|
||||
return _list_node
|
||||
return decorator
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------------------------------
|
||||
#
|
||||
# Simple input shortcuts
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue