Update the multidesc contrib to support named descs and adding descs together to form a final desc. This means the format for the multidesc storage has changed, so if you tested it already, delete the .db.multidesc attribute and reload the server.

This commit is contained in:
Griatch 2016-06-26 14:21:19 +02:00
parent 96542418c0
commit a95e32b372

View file

@ -26,94 +26,122 @@ Reload the server and you should have the +desc command available (it
will replace the default `desc` command). will replace the default `desc` command).
""" """
import re
from evennia import default_cmds from evennia import default_cmds
from evennia.utils.utils import crop from evennia.utils.utils import crop
from evennia.utils.eveditor import EvEditor from evennia.utils.eveditor import EvEditor
# regex for the set functionality
_RE_KEYS = re.compile(r"([\w\s]+)(?:\+*?)", re.U + re.I)
# Helper functions for the Command # Helper functions for the Command
class DescValidateError(ValueError):
"Used for tracebacks from desc systems"
pass
def _update_store(caller, num=0, text=None, replace=False): def _get_desc(caller, key, raise_error=False):
"""
Retrieve description from storage
Args:
caller (Object): The caller with the description
key (str): The desc-key to search for
raise_error (bool, optional): Raise an exception
when not finding the description.
Returns:
desc (str): The matching description or `None` if
`raise_error` is false
Raises:
DescValidateError: If desc is not found and raise_error=True.
"""
if not caller.db.multidesc:
_update_store(caller)
key = key.lower()
for mkey, desc in caller.db.multidesc:
if mkey == key:
return desc
if raise_error:
raise DescValidateError("Description key '%s' not found." % key)
return None
def _update_store(caller, key=None, desc=None, delete=False, swapkey=None):
""" """
Helper function for updating the database store. Helper function for updating the database store.
Args: Args:
caller (Object): The caller of the command. caller (Object): The caller of the command.
num (int): Index of store to update. key (str): Description identifier
text (str): Description text. desc (str): Description text.
replace (bool): Replace or amend description. delete (bool): Delete given key.
swapkey (str): Swap list positions of `key` and this key.
""" """
if not caller.db.multidesc: if not caller.db.multidesc:
# initialize the multidesc attribute # initialize the multidesc attribute
caller.db.multidesc = [caller.db.desc or ""] caller.db.multidesc = [("caller", caller.db.desc or "")]
if not text: if not key:
return return
if replace: lokey = key.lower()
caller.db.multidesc[num] = text match = [ind for ind, tup in enumerate(caller.db.multidesc) if tup[0] == lokey]
if match:
idesc = match[0]
if delete:
# delete entry
del caller.db.multidesc[idesc]
elif swapkey:
# swap positions
loswapkey = swapkey.lower()
swapmatch = [ind for ind, tup in enumerate(caller.db.multidesc) if tup[0] == loswapkey]
if swapmatch:
iswap = swapmatch[0]
if idesc == iswap:
raise DescValidateError("Swapping a key with itself does nothing.")
temp = caller.db.multidesc[idesc]
caller.db.multidesc[idesc] = caller.db.multidesc[iswap]
caller.db.multidesc[iswap] = temp
else:
raise DescValidateError("Description key '|w%s|n' not found." % swapkey)
elif desc:
# update in-place
caller.db.multidesc[idesc] = (lokey, desc)
else:
raise DescValidateError("No description was set.")
else: else:
caller.db.multidesc.insert(num, text) # no matching key
if delete or swapkey:
raise DescValidateError("Description key '|w%s|n' not found." % key)
class NumValidateError(ValueError): elif desc:
"Used for tracebacks from _validate_num" # insert new at the top of the stack
pass caller.db.multidesc.insert(0, (lokey, desc))
else:
raise DescValidateError("No description was set.")
def _validate_num(caller, num):
"""
Check so the given num is a valid number in the storage interval.
Args:
caller (Object): The caller of the command
num (str): The number to validate.
Returns:
num (int): Returns the valid index (starting from 0)
Raises:
NumValidateError: For malformed numbers.
Notes:
This function will also report errors.
"""
if not caller.db.multidesc:
_update_store(caller)
nlen = len(caller.db.multidesc)
if not num.strip().isdigit() or not (0 < int(num) <= nlen):
raise NumValidateError("%s must be a number between 1 and %i." %
('%s' % num or "Argument", nlen))
else:
return int(num) - 1
# eveditor save/load/quit functions # eveditor save/load/quit functions
def _save_editor(caller, buffer): def _save_editor(caller, buffer):
"Called when the editor saves its contents" "Called when the editor saves its contents"
num = caller.db._multidesc_editnum key = caller.db._multidesc_editkey
replace = caller.db._multidesc_editreplace _update_store(caller, key, buffer)
if num is not None: caller.msg("Saved description to key '%s'." % key)
_update_store(caller, num, buffer, replace=replace) return True
caller.msg("Saved the buffer to description slot %i." % (num + 1))
return True
def _load_editor(caller): def _load_editor(caller):
"Called when the editor loads contents" "Called when the editor loads contents"
num = caller.db._multidesc_editnum key = caller.db._multidesc_editkey
if num is not None: match = [ind for ind, tup in enumerate(caller.db.multidesc) if tup[0] == key]
try: if match:
return caller.db.multidesc[num] return caller.db.multidesc[match[0]][1]
except IndexError:
pass
return "" return ""
def _quit_editor(caller): def _quit_editor(caller):
"Called when the editor quits" "Called when the editor quits"
del caller.db._multidesc_editnum del caller.db._multidesc_editkey
del caller.db._multidesc_editreplace
caller.msg("Exited editor.") caller.msg("Exited editor.")
@ -124,14 +152,21 @@ class CmdMultiDesc(default_cmds.MuxCommand):
Manage multiple descriptions Manage multiple descriptions
Usage: Usage:
+desc [n] - show current or desc <n> +desc [key] - show current desc desc with <key>
+desc/list - list descriptions (abbreviated) +desc <key> = <text> - add/replace desc with <key>
+desc/list/full - list descriptions (full texts) +desc/list - list descriptions (abbreviated)
+desc/add [<n> =] <text> - add new desc or replace desc <n> +desc/list/full - list descriptions (full texts)
+desc/edit [n] - open editor to modify current or desc <n> +desc/edit <key> - add/edit desc <key> in line editor
+desc/del [n] - delete current or desc <n> +desc/del <key> - delete desc <key>
+desc/swap <n1>-<n2> - reorder list by swapping #n1 and <n2> +desc/swap <key1>-<key2> - swap positions of <key1> and <key2> in list
+desc/set <n> - set which desc <n> as active desc +desc/set <key> [+key+...] - set desc as default or combine multiple descs
Notes:
When combining multiple descs with +desc/set <key> + <key2> + ...,
you can add custom text between the '+' signs. Any text
not a '+' or identified a as a desc key will be added to the
final string. Use e.g. ansi line break ||/ to add a new
paragraph. Whitespace around keys (only) will be stripped.
""" """
key = "+desc" key = "+desc"
@ -155,83 +190,93 @@ class CmdMultiDesc(default_cmds.MuxCommand):
# Note that we list starting from 1, not from 0. # Note that we list starting from 1, not from 0.
_update_store(caller) _update_store(caller)
do_crop = not "full" in switches do_crop = not "full" in switches
outtext = "|wStored descs:|n" if do_crop:
for inum, desc in enumerate(caller.db.multidesc): outtext = ["|w%s:|n %s" % (key, crop(desc))
outtext += "\n|w%i:|n %s" % (inum + 1, crop(desc) if do_crop else "\n%s" % desc) for key, desc in caller.db.multidesc]
caller.msg(outtext)
elif "add" in switches:
# add text directly to a new entry or an existing one.
if self.rhs:
# this means a '=' was given
num, desc = _validate_num(caller, self.lhs), self.rhs
replace = True
else: else:
num, desc = 0, self.args outtext = ["\n|w%s:|n|n\n%s\n%s" % (key, "-" * (len(key) + 1), desc)
replace = False for key, desc in caller.db.multidesc]
if not desc:
caller.msg("No description given.") caller.msg("|wStored descs:|n\n" + "\n".join(outtext))
return return
_update_store(caller, num, desc, replace=replace)
caller.msg("Stored description in slot %i: \"%s\"" % (num + 1, crop(desc)))
elif "edit" in switches: elif "edit" in switches:
# Use the eveditor to edit the description. # Use the eveditor to edit/create the named description
if args: if not args:
num = _validate_num(caller, args) caller.msg("Usage: %s/edit key" % self.key)
replace = True return
else:
num = 1
replace = False
# this is used by the editor to know what to edit; it's deleted automatically # this is used by the editor to know what to edit; it's deleted automatically
caller.db._multidesc_editnum = num caller.db._multidesc_editkey = args
caller.db._multidesc_editreplace = replace
# start the editor # start the editor
EvEditor(caller, loadfunc=_load_editor, savefunc=_save_editor, EvEditor(caller, loadfunc=_load_editor, savefunc=_save_editor,
quitfunc=_quit_editor, key="multidesc editor", persistent=True) quitfunc=_quit_editor, key="multidesc editor", persistent=True)
elif "delete" in switches or "del" in switches: elif "delete" in switches or "del" in switches:
# delete a multidesc entry. # delete a multidesc entry.
num = _validate_num(caller, args) if not args:
del caller.db.multidesc[num] caller.msg("Usage: %s/delete key" % self.key)
caller.msg("Deleted description number %i." % (num + 1)) return
_update_store(caller, args, delete=True)
caller.msg("Deleted description with key '%s'." % args)
elif "swap" in switches or "switch" in switches or "reorder" in switches: elif "swap" in switches or "switch" in switches or "reorder" in switches:
# Reorder list by swapping two entries. We expect numbers starting from 1 # Reorder list by swapping two entries. We expect numbers starting from 1
nums = [_validate_num(caller, arg) for arg in args.split("-", 1)] keys = [arg for arg in args.split("-", 1)]
if not len(nums) == 2: if not len(keys) == 2:
caller.msg("To swap two desc entries, use |w%s/swap <num1> - <num2>|n" % (self.key)) caller.msg("Usage: %s/swap key1-key2" % self.key)
return
num1, num2 = nums
if num1 == num2:
caller.msg("Swapping position with itself changes nothing.")
return return
key1, key2 = keys
# perform the swap # perform the swap
desc1, desc2 = caller.db.multidesc[num1], caller.db.multidesc[num2] _update_store(caller, key1, swapkey=key2)
caller.db.multidesc[num2] = desc1 caller.msg("Swapped descs '%s' and '%s'." % (key1, key2))
caller.db.multidesc[num1] = desc2
caller.msg("Swapped descs numbers %i and %i." % (num1 + 1, num2 + 1))
elif "set" in switches: elif "set" in switches:
# switches one of the multidescs to be the "active", # switches one (or more) of the multidescs to be the "active" description
# description, with numbers starting from 1 _update_store(caller)
if args: if not args:
num = _validate_num(caller, args) caller.msg("Usage: %s/set key [+ key2 + key3 + ...]" % self.key)
else: return
_update_store(caller) new_desc = []
num = 0 multidesc = caller.db.multidesc
# activating this description for key in args.split("+"):
caller.db.desc = caller.db.multidesc[num] notfound = True
caller.msg("|wSet description %i as the current one:|n\n%s" % (num + 1, crop(caller.db.desc))) lokey = key.strip().lower()
for mkey, desc in multidesc:
if lokey == mkey:
new_desc.append(desc)
notfound = False
continue
if notfound:
# if we get here, there is no desc match, we add it as a normal string
new_desc.append(key)
new_desc = "".join(new_desc)
caller.db.desc = new_desc
caller.msg("%s\n\n|wThe above was set as the current description.|n" % new_desc)
elif self.rhs or "add" in switches:
# add text directly to a new entry or an existing one.
if not (self.lhs and self.rhs):
caller.msg("Usage: %s/add key = description" % self.key)
return
key, desc = self.lhs, self.rhs
_update_store(caller, key, desc)
caller.msg("Stored description '%s': \"%s\"" % (key, crop(desc)))
else: else:
# display the current description or a numbered description # display the current description or a numbered description
_update_store(caller)
if args: if args:
num = _validate_num(caller, args) key = args.lower()
caller.msg("|wDecsription number %i:|n\n%s" % (num + 1, caller.db.multidesc[num])) multidesc = caller.db.multidesc
for mkey, desc in multidesc:
if key == mkey:
caller.msg("|wDecsription %s:|n\n%s" % (key, desc))
return
caller.msg("Description key '%s' not found." % key)
else: else:
caller.msg("|wCurrent desc:|n\n%s" % caller.db.desc) caller.msg("|wCurrent desc:|n\n%s" % caller.db.desc)
except NumValidateError, err: except DescValidateError, err:
# This is triggered by _validate_num # This is triggered by _key_to_index
caller.msg(err) caller.msg(err)