Merge conflicts against master, including cmdhandler support for direct cmdobject input together with prefix-ignore mechanism from devel.

This commit is contained in:
Griatch 2017-04-01 16:08:23 +02:00
commit a648433db8
69 changed files with 2617 additions and 1771 deletions

View file

@ -18,12 +18,12 @@ Example usage:
Where `caller` is the Object to use the menu on - it will get a new
cmdset while using the Menu. The menu_module_path is the python path
to a python module containing function defintions. By adjusting the
to a python module containing function definitions. By adjusting the
keyword options of the Menu() initialization call you can start the
menu at different places in the menu definition file, adjust if the
menu command should overload the normal commands or not, etc.
The `perstent` keyword will make the menu survive a server reboot.
The `persistent` keyword will make the menu survive a server reboot.
It is `False` by default. Note that if using persistent mode, every
node and callback in the menu must be possible to be *pickled*, this
excludes e.g. callables that are class methods or functions defined
@ -31,7 +31,7 @@ dynamically or as part of another function. In non-persistent mode
no such restrictions exist.
The menu is defined in a module (this can be the same module as the
command definition too) with function defintions:
command definition too) with function definitions:
```python
@ -181,8 +181,7 @@ _HELP_NO_OPTIONS = _("Commands: help, quit")
_HELP_NO_OPTIONS_NO_QUIT = _("Commands: help")
_HELP_NO_OPTION_MATCH = _("Choose an option or try 'help'.")
_ERROR_PERSISTENT_SAVING = \
"""
_ERROR_PERSISTENT_SAVING = """
{error}
|rThe menu state could not be saved for persistent mode. Switching
@ -190,10 +189,9 @@ to non-persistent mode (which means the menu session won't survive
an eventual server reload).|n
"""
_TRACE_PERSISTENT_SAVING = \
"EvMenu persistent-mode error. Commonly, this is because one or " \
"more of the EvEditor callbacks could not be pickled, for example " \
"because it's a class method or is defined inside another function."
_TRACE_PERSISTENT_SAVING = "EvMenu persistent-mode error. Commonly, this is because one or " \
"more of the EvEditor callbacks could not be pickled, for example " \
"because it's a class method or is defined inside another function."
class EvMenuError(RuntimeError):
@ -203,11 +201,12 @@ class EvMenuError(RuntimeError):
"""
pass
#------------------------------------------------------------
# -------------------------------------------------------------
#
# Menu command and command set
#
#------------------------------------------------------------
# -------------------------------------------------------------
class CmdEvMenuNode(Command):
"""
@ -227,7 +226,11 @@ class CmdEvMenuNode(Command):
# this will re-start a completely new evmenu call.
saved_options = caller.attributes.get("_menutree_saved")
if saved_options:
startnode, startnode_input = caller.attributes.get("_menutree_saved_startnode")
startnode_tuple = caller.attributes.get("_menutree_saved_startnode")
try:
startnode, startnode_input = startnode_tuple
except ValueError: # old form of startnode store
startnode, startnode_input = startnode_tuple, ""
if startnode:
saved_options[2]["startnode"] = startnode
saved_options[2]["startnode_input"] = startnode_input
@ -254,7 +257,7 @@ class CmdEvMenuNode(Command):
menu = caller.ndb._menutree
if not menu:
# can't restore from a session
err = "Menu object not found as %s.ndb._menutree!" % (orig_caller)
err = "Menu object not found as %s.ndb._menutree!" % orig_caller
orig_caller.msg(err) # don't give the session as a kwarg here, direct to original
raise EvMenuError(err)
# we must do this after the caller with the menui has been correctly identified since it
@ -287,7 +290,8 @@ class EvMenuCmdSet(CmdSet):
#
# Menu main class
#
#------------------------------------------------------------
# -------------------------------------------------------------
class EvMenu(object):
"""
@ -436,7 +440,17 @@ class EvMenu(object):
"persistent": persistent}
calldict.update(kwargs)
try:
caller.attributes.add("_menutree_saved", ( self.__class__, (menudata, ), calldict ))
caller.attributes.add("_menutree_saved",
((menudata, ),
{"startnode": startnode,
"cmdset_mergetype": cmdset_mergetype,
"cmdset_priority": cmdset_priority,
"auto_quit": auto_quit, "auto_look": auto_look, "auto_help": auto_help,
"cmd_on_exit": cmd_on_exit,
"nodetext_formatter": nodetext_formatter,
"options_formatter": options_formatter,
"node_formatter": node_formatter, "input_parser": input_parser,
"persistent": persistent, }))
caller.attributes.add("_menutree_saved_startnode", (startnode, startnode_input))
except Exception as err:
caller.msg(_ERROR_PERSISTENT_SAVING.format(error=err), session=self._session)
@ -505,7 +519,6 @@ class EvMenu(object):
# format the entire node
return self.node_formatter(nodetext, optionstext)
def _execute_node(self, nodename, raw_string):
"""
Execute a node.
@ -542,15 +555,12 @@ class EvMenu(object):
raise
return nodetext, options
def display_nodetext(self):
self.caller.msg(self.nodetext, session=self._session)
def display_helptext(self):
self.caller.msg(self.helptext, session=self._session)
def callback_goto(self, callback, goto, raw_string):
"""
Call callback and goto in sequence.
@ -860,25 +870,29 @@ class CmdGetInput(Command):
aliases = _CMD_NOINPUT
def func(self):
"This is called when user enters anything."
"""This is called when user enters anything."""
caller = self.caller
callback = caller.ndb._getinput._callback
if not callback:
# this can be happen if called from a player-command when IC
caller = self.player
callback = caller.ndb._getinput._callback
if not callback:
raise RuntimeError("No input callback found.")
try:
getinput = caller.ndb._getinput
if not getinput and hasattr(caller, "player"):
getinput = caller.player.ndb._getinput
caller = caller.player
callback = getinput._callback
caller.ndb._getinput._session = self.session
prompt = caller.ndb._getinput._prompt
result = self.raw_string.strip() # we strip the ending line break caused by sending
caller.ndb._getinput._session = self.session
prompt = caller.ndb._getinput._prompt
result = self.raw_string.strip() # we strip the ending line break caused by sending
ok = not callback(caller, prompt, result)
if ok:
# only clear the state if the callback does not return
# anything
del caller.ndb._getinput
ok = not callback(caller, prompt, result)
if ok:
# only clear the state if the callback does not return
# anything
del caller.ndb._getinput
caller.cmdset.remove(InputCmdSet)
except Exception:
# make sure to clean up cmdset if something goes wrong
caller.msg("|rError in get_input. Choice not confirmed (report to admin)|n")
logger.log_trace("Error in get_input")
caller.cmdset.remove(InputCmdSet)
@ -894,12 +908,12 @@ class InputCmdSet(CmdSet):
no_channels = False
def at_cmdset_creation(self):
"called once at creation"
"""called once at creation"""
self.add(CmdGetInput())
class _Prompt(object):
"Dummy holder"
"""Dummy holder"""
pass
@ -958,11 +972,11 @@ def get_input(caller, prompt, callback, session=None):
caller.msg(prompt, session=session)
#------------------------------------------------------------
# -------------------------------------------------------------
#
# test menu strucure and testing command
#
#------------------------------------------------------------
# -------------------------------------------------------------
def test_start_node(caller):
menu = caller.ndb._menutree
@ -978,17 +992,17 @@ def test_start_node(caller):
The menu was initialized with two variables: %s and %s.
""" % (menu.testval, menu.testval2)
options = ({"key": ("{yS{net", "s"),
options = ({"key": ("|yS|net", "s"),
"desc": "Set an attribute on yourself.",
"exec": lambda caller: caller.attributes.add("menuattrtest", "Test value"),
"goto": "test_set_node"},
{"key": ("{yL{nook", "l"),
{"key": ("|yL|nook", "l"),
"desc": "Look and see a custom message.",
"goto": "test_look_node"},
{"key": ("{yV{niew", "v"),
{"key": ("|yV|niew", "v"),
"desc": "View your own name",
"goto": "test_view_node"},
{"key": ("{yQ{nuit", "quit", "q", "Q"),
{"key": ("|yQ|nuit", "quit", "q", "Q"),
"desc": "Quit this menu example.",
"goto": "test_end_node"},
{"key": "_default",
@ -998,16 +1012,17 @@ def test_start_node(caller):
def test_look_node(caller):
text = ""
options = {"key": ("{yL{nook", "l"),
options = {"key": ("|yL|nook", "l"),
"desc": "Go back to the previous menu.",
"goto": "test_start_node"}
return text, options
def test_set_node(caller):
text = ("""
The attribute 'menuattrtest' was set to
{w%s{n
|w%s|n
(check it with examine after quitting the menu).
@ -1015,9 +1030,8 @@ def test_set_node(caller):
string "_default", meaning it will catch any input, in this case
to return to the main menu. So you can e.g. press <return> to go
back now.
""" % caller.db.menuattrtest,
# optional help text for this node
"""
""" % caller.db.menuattrtest, # optional help text for this node
"""
This is the help entry for this node. It is created by returning
the node text as a tuple - the second string in that tuple will be
used as the help text.
@ -1031,7 +1045,7 @@ def test_set_node(caller):
def test_view_node(caller):
text = """
Your name is {g%s{n!
Your name is |g%s|n!
click |lclook|lthere|le to trigger a look command under MXP.
This node's option has no explicit key (nor the "_default" key
@ -1044,11 +1058,11 @@ def test_view_node(caller):
return text, options
def test_displayinput_node(caller, raw_string):
def test_displayinput_node(caller, raw_string):
text = """
You entered the text:
"{w%s{n"
"|w%s|n"
... which could now be handled or stored here in some way if this
was not just an example.
@ -1059,7 +1073,7 @@ def test_displayinput_node(caller, raw_string):
to the start node.
""" % raw_string
options = {"key": "_default",
"goto": "test_start_node"}
"goto": "test_start_node"}
return text, options
@ -1089,5 +1103,5 @@ class CmdTestMenu(Command):
self.caller.msg("Usage: testmenu menumodule")
return
# start menu
EvMenu(self.caller, self.args.strip(), startnode="test_start_node", persistent=True, cmdset_mergetype="Replace",
testval="val", testval2="val2")
EvMenu(self.caller, self.args.strip(), startnode="test_start_node", persistent=True,
cmdset_mergetype="Replace", testval="val", testval2="val2")