mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
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:
parent
96542418c0
commit
a95e32b372
1 changed files with 165 additions and 120 deletions
|
|
@ -26,94 +26,122 @@ Reload the server and you should have the +desc command available (it
|
|||
will replace the default `desc` command).
|
||||
|
||||
"""
|
||||
import re
|
||||
from evennia import default_cmds
|
||||
from evennia.utils.utils import crop
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
Args:
|
||||
caller (Object): The caller of the command.
|
||||
num (int): Index of store to update.
|
||||
text (str): Description text.
|
||||
replace (bool): Replace or amend description.
|
||||
key (str): Description identifier
|
||||
desc (str): Description text.
|
||||
delete (bool): Delete given key.
|
||||
swapkey (str): Swap list positions of `key` and this key.
|
||||
|
||||
"""
|
||||
if not caller.db.multidesc:
|
||||
# initialize the multidesc attribute
|
||||
caller.db.multidesc = [caller.db.desc or ""]
|
||||
if not text:
|
||||
caller.db.multidesc = [("caller", caller.db.desc or "")]
|
||||
if not key:
|
||||
return
|
||||
if replace:
|
||||
caller.db.multidesc[num] = text
|
||||
lokey = key.lower()
|
||||
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:
|
||||
caller.db.multidesc.insert(num, text)
|
||||
|
||||
|
||||
class NumValidateError(ValueError):
|
||||
"Used for tracebacks from _validate_num"
|
||||
pass
|
||||
|
||||
|
||||
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
|
||||
|
||||
# no matching key
|
||||
if delete or swapkey:
|
||||
raise DescValidateError("Description key '|w%s|n' not found." % key)
|
||||
elif desc:
|
||||
# insert new at the top of the stack
|
||||
caller.db.multidesc.insert(0, (lokey, desc))
|
||||
else:
|
||||
raise DescValidateError("No description was set.")
|
||||
|
||||
# eveditor save/load/quit functions
|
||||
|
||||
def _save_editor(caller, buffer):
|
||||
"Called when the editor saves its contents"
|
||||
num = caller.db._multidesc_editnum
|
||||
replace = caller.db._multidesc_editreplace
|
||||
if num is not None:
|
||||
_update_store(caller, num, buffer, replace=replace)
|
||||
caller.msg("Saved the buffer to description slot %i." % (num + 1))
|
||||
return True
|
||||
key = caller.db._multidesc_editkey
|
||||
_update_store(caller, key, buffer)
|
||||
caller.msg("Saved description to key '%s'." % key)
|
||||
return True
|
||||
|
||||
def _load_editor(caller):
|
||||
"Called when the editor loads contents"
|
||||
num = caller.db._multidesc_editnum
|
||||
if num is not None:
|
||||
try:
|
||||
return caller.db.multidesc[num]
|
||||
except IndexError:
|
||||
pass
|
||||
key = caller.db._multidesc_editkey
|
||||
match = [ind for ind, tup in enumerate(caller.db.multidesc) if tup[0] == key]
|
||||
if match:
|
||||
return caller.db.multidesc[match[0]][1]
|
||||
return ""
|
||||
|
||||
def _quit_editor(caller):
|
||||
"Called when the editor quits"
|
||||
del caller.db._multidesc_editnum
|
||||
del caller.db._multidesc_editreplace
|
||||
del caller.db._multidesc_editkey
|
||||
caller.msg("Exited editor.")
|
||||
|
||||
|
||||
|
|
@ -124,14 +152,21 @@ class CmdMultiDesc(default_cmds.MuxCommand):
|
|||
Manage multiple descriptions
|
||||
|
||||
Usage:
|
||||
+desc [n] - show current or desc <n>
|
||||
+desc/list - list descriptions (abbreviated)
|
||||
+desc/list/full - list descriptions (full texts)
|
||||
+desc/add [<n> =] <text> - add new desc or replace desc <n>
|
||||
+desc/edit [n] - open editor to modify current or desc <n>
|
||||
+desc/del [n] - delete current or desc <n>
|
||||
+desc/swap <n1>-<n2> - reorder list by swapping #n1 and <n2>
|
||||
+desc/set <n> - set which desc <n> as active desc
|
||||
+desc [key] - show current desc desc with <key>
|
||||
+desc <key> = <text> - add/replace desc with <key>
|
||||
+desc/list - list descriptions (abbreviated)
|
||||
+desc/list/full - list descriptions (full texts)
|
||||
+desc/edit <key> - add/edit desc <key> in line editor
|
||||
+desc/del <key> - delete desc <key>
|
||||
+desc/swap <key1>-<key2> - swap positions of <key1> and <key2> in list
|
||||
+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"
|
||||
|
|
@ -155,83 +190,93 @@ class CmdMultiDesc(default_cmds.MuxCommand):
|
|||
# Note that we list starting from 1, not from 0.
|
||||
_update_store(caller)
|
||||
do_crop = not "full" in switches
|
||||
outtext = "|wStored descs:|n"
|
||||
for inum, desc in enumerate(caller.db.multidesc):
|
||||
outtext += "\n|w%i:|n %s" % (inum + 1, crop(desc) if do_crop else "\n%s" % desc)
|
||||
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
|
||||
if do_crop:
|
||||
outtext = ["|w%s:|n %s" % (key, crop(desc))
|
||||
for key, desc in caller.db.multidesc]
|
||||
else:
|
||||
num, desc = 0, self.args
|
||||
replace = False
|
||||
if not desc:
|
||||
caller.msg("No description given.")
|
||||
return
|
||||
_update_store(caller, num, desc, replace=replace)
|
||||
caller.msg("Stored description in slot %i: \"%s\"" % (num + 1, crop(desc)))
|
||||
outtext = ["\n|w%s:|n|n\n%s\n%s" % (key, "-" * (len(key) + 1), desc)
|
||||
for key, desc in caller.db.multidesc]
|
||||
|
||||
caller.msg("|wStored descs:|n\n" + "\n".join(outtext))
|
||||
return
|
||||
|
||||
elif "edit" in switches:
|
||||
# Use the eveditor to edit the description.
|
||||
if args:
|
||||
num = _validate_num(caller, args)
|
||||
replace = True
|
||||
else:
|
||||
num = 1
|
||||
replace = False
|
||||
# Use the eveditor to edit/create the named description
|
||||
if not args:
|
||||
caller.msg("Usage: %s/edit key" % self.key)
|
||||
return
|
||||
|
||||
# this is used by the editor to know what to edit; it's deleted automatically
|
||||
caller.db._multidesc_editnum = num
|
||||
caller.db._multidesc_editreplace = replace
|
||||
caller.db._multidesc_editkey = args
|
||||
# start the editor
|
||||
EvEditor(caller, loadfunc=_load_editor, savefunc=_save_editor,
|
||||
quitfunc=_quit_editor, key="multidesc editor", persistent=True)
|
||||
|
||||
elif "delete" in switches or "del" in switches:
|
||||
# delete a multidesc entry.
|
||||
num = _validate_num(caller, args)
|
||||
del caller.db.multidesc[num]
|
||||
caller.msg("Deleted description number %i." % (num + 1))
|
||||
if not args:
|
||||
caller.msg("Usage: %s/delete key" % self.key)
|
||||
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:
|
||||
# Reorder list by swapping two entries. We expect numbers starting from 1
|
||||
nums = [_validate_num(caller, arg) for arg in args.split("-", 1)]
|
||||
if not len(nums) == 2:
|
||||
caller.msg("To swap two desc entries, use |w%s/swap <num1> - <num2>|n" % (self.key))
|
||||
return
|
||||
num1, num2 = nums
|
||||
if num1 == num2:
|
||||
caller.msg("Swapping position with itself changes nothing.")
|
||||
keys = [arg for arg in args.split("-", 1)]
|
||||
if not len(keys) == 2:
|
||||
caller.msg("Usage: %s/swap key1-key2" % self.key)
|
||||
return
|
||||
key1, key2 = keys
|
||||
# perform the swap
|
||||
desc1, desc2 = caller.db.multidesc[num1], caller.db.multidesc[num2]
|
||||
caller.db.multidesc[num2] = desc1
|
||||
caller.db.multidesc[num1] = desc2
|
||||
caller.msg("Swapped descs numbers %i and %i." % (num1 + 1, num2 + 1))
|
||||
_update_store(caller, key1, swapkey=key2)
|
||||
caller.msg("Swapped descs '%s' and '%s'." % (key1, key2))
|
||||
|
||||
elif "set" in switches:
|
||||
# switches one of the multidescs to be the "active",
|
||||
# description, with numbers starting from 1
|
||||
if args:
|
||||
num = _validate_num(caller, args)
|
||||
else:
|
||||
_update_store(caller)
|
||||
num = 0
|
||||
# activating this description
|
||||
caller.db.desc = caller.db.multidesc[num]
|
||||
caller.msg("|wSet description %i as the current one:|n\n%s" % (num + 1, crop(caller.db.desc)))
|
||||
# switches one (or more) of the multidescs to be the "active" description
|
||||
_update_store(caller)
|
||||
if not args:
|
||||
caller.msg("Usage: %s/set key [+ key2 + key3 + ...]" % self.key)
|
||||
return
|
||||
new_desc = []
|
||||
multidesc = caller.db.multidesc
|
||||
for key in args.split("+"):
|
||||
notfound = True
|
||||
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:
|
||||
# display the current description or a numbered description
|
||||
_update_store(caller)
|
||||
if args:
|
||||
num = _validate_num(caller, args)
|
||||
caller.msg("|wDecsription number %i:|n\n%s" % (num + 1, caller.db.multidesc[num]))
|
||||
key = args.lower()
|
||||
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:
|
||||
caller.msg("|wCurrent desc:|n\n%s" % caller.db.desc)
|
||||
|
||||
except NumValidateError, err:
|
||||
# This is triggered by _validate_num
|
||||
except DescValidateError, err:
|
||||
# This is triggered by _key_to_index
|
||||
caller.msg(err)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue