Added @cset command for changing a channel's access restriction settings. Added @cboot and a few more missing channel commands. Cleaned out the utils commands and fixed formatting on a few default commands.

This commit is contained in:
Griatch 2011-04-21 10:29:24 +00:00
parent 7f7016ad7d
commit 7b43c4a608
8 changed files with 265 additions and 411 deletions

View file

@ -163,6 +163,7 @@ class CmdSetHandler(object):
"Display current commands"
string = ""
merged = False
if len(self.cmdset_stack) > 1:
# We have more than one cmdset in stack; list them all
num = 0
@ -175,17 +176,18 @@ class CmdSetHandler(object):
string += "\n %i: <%s (%s, prio %i)>: %s" % \
(snum, cmdset.key, mergetype,
cmdset.priority, cmdset)
string += "\n (combining %i cmdsets):" % (num+1)
else:
string += "\n "
string += "\n"
merged = True
# Display the currently active cmdset
mergetype = self.mergetype_stack[-1]
if mergetype != self.current.mergetype:
merged_on = self.cmdset_stack[-2].key
mergetype = "custom %s on %s" % (mergetype, merged_on)
string += " <%s (%s)> %s" % (self.current.key,
mergetype, self.current)
if merged:
string += " <Merged (%s)>: %s" % (mergetype, self.current)
else:
string += " <%s (%s)>: %s" % (self.current.key, mergetype, self.current)
return string.strip()
def update(self, init_mode=False):

View file

@ -1414,18 +1414,6 @@ class CmdExamine(ObjManipCommand):
locks = "cmd:perm(examine) or perm(Builders)"
help_category = "Building"
def crop_line(self, text, heading="", line_width=79):
"""
Crops a line of text, adding [...] if doing so.
heading + text + eventual [...] will not exceed line_width.
"""
headlen = len(str(heading))
textlen = len(str(text))
if textlen > (line_width - headlen):
text = "%s[...]" % text[:line_width - headlen - 5]
return text
def format_attributes(self, obj, attrname=None, crop=True):
"""
Helper function that returns info about attributes and/or
@ -1449,13 +1437,13 @@ class CmdExamine(ObjManipCommand):
string += "\n{wPersistent attributes{n:"
for attr, value in db_attr:
if crop:
value = self.crop_line(value, attr)
value = utils.crop(value)
string += "\n %s = %s" % (attr, value)
if ndb_attr and ndb_attr[0]:
string += "\n{wNon-persistent attributes{n:"
for attr, value in ndb_attr:
if crop:
value = self.crop_line(value, attr)
value = utils.crop(value)
string += "\n %s = %s" % (attr, value)
return string
@ -1466,11 +1454,14 @@ class CmdExamine(ObjManipCommand):
returns a string.
"""
string = "\n{wName/key{n: %s (#%i)" % (obj.name, obj.id)
if obj.has_player:
string = "\n{wName/key{n: {c%s{n (%s)" % (obj.name, obj.dbref)
else:
string = "\n{wName/key{n: {C%s{n (%s)" % (obj.name, obj.dbref)
if obj.aliases:
string += "\n{wAliases{n: %s" % (", ".join(obj.aliases))
if obj.has_player:
string += "\n{wPlayer{n: %s" % obj.player.name
string += "\n{wPlayer{n: {c%s{n" % obj.player.name
perms = obj.player.permissions
if obj.player.is_superuser:
perms = ["<Superuser>"]
@ -1487,9 +1478,11 @@ class CmdExamine(ObjManipCommand):
string += "\n{wPermissions{n: %s" % (", ".join(perms))
locks = str(obj.locks)
if locks:
string += "\n{wLocks{n: %s" % ("; ".join([lock for lock in locks.split(';')]))
string += "\n{wLocks{n:" + utils.fill("; ".join([lock for lock in locks.split(';')]), indent=6)
if not (len(obj.cmdset.all()) == 1 and obj.cmdset.current.key == "Empty"):
string += "\n{wCurrent Cmdset (before permission checks){n:\n %s" % obj.cmdset
cmdsetstr = "\n".join([utils.fill(cmdset, indent=2) for cmdset in str(obj.cmdset).split("\n")])
string += "\n{wCurrent Cmdset (before permission checks){n:\n %s" % cmdsetstr
if obj.scripts.all():
string += "\n{wScripts{n:\n %s" % obj.scripts
# add the attributes
@ -1514,7 +1507,7 @@ class CmdExamine(ObjManipCommand):
string += "\n{wContents{n: " + ", ".join([cont.name for cont in obj.contents
if cont not in exits and cont not in pobjs])
#output info
return "-"*50 + '\n' + string.strip() + "\n" + '-'*50
return "-"*78 + '\n' + string.strip() + "\n" + '-'*78
def func(self):
"Process command"

View file

@ -3,7 +3,7 @@ This module ties together all the commands of the default command set.
"""
from src.commands.cmdset import CmdSet
from src.commands.default import general, help, admin, system
from src.commands.default import utils, comms, building
from src.commands.default import comms, building
from src.commands.default import batchprocess
class DefaultCmdSet(CmdSet):
@ -87,6 +87,10 @@ class DefaultCmdSet(CmdSet):
self.add(comms.CmdChannels())
self.add(comms.CmdCdestroy())
self.add(comms.CmdChannelCreate())
self.add(comms.CmdCset())
self.add(comms.CmdCBoot())
self.add(comms.CmdCemit())
self.add(comms.CmdCWho())
self.add(comms.CmdCdesc())
self.add(comms.CmdPage())
self.add(comms.CmdIRC2Chan())
@ -97,8 +101,3 @@ class DefaultCmdSet(CmdSet):
# Batchprocessor commands
self.add(batchprocess.CmdBatchCommands())
self.add(batchprocess.CmdBatchCode())
# Testing/Utility commands
self.add(utils.CmdTest())
#self.add(utils.CmdTestPerms())
self.add(utils.TestCom())

View file

@ -16,6 +16,9 @@ def find_channel(caller, channelname, silent=False):
"""
channels = Channel.objects.channel_search(channelname)
if not channels:
channels = [chan for chan in Channel.objects.all() if channelname in chan.aliases]
if channels:
return channels[0]
if not silent:
caller.msg("Channel '%s' not found." % channelname)
return None
@ -223,7 +226,7 @@ class CmdChannels(MuxCommand):
key = "@channels"
aliases = ["@clist", "channels", "comlist", "chanlist", "channellist", "all channels"]
help_category = "Comms"
locks = "cmd:all()"
locks = "cmd: not perm(channel_banned)"
def func(self):
"Implement function"
@ -291,7 +294,7 @@ class CmdCdestroy(MuxCommand):
key = "@cdestroy"
help_category = "Comms"
locks = "cmd:all()"
locks = "cmd: not perm(channel_banned)"
def func(self):
"Destroy objects cleanly."
@ -315,226 +318,146 @@ class CmdCdestroy(MuxCommand):
CHANNELHANDLER.update()
caller.msg("%s was destroyed." % channel)
class CmdCBoot(MuxCommand):
"""
@cboot
## def cmd_cset(self):
## """
## @cset
Usage:
@cboot[/quiet] <channel> = <player> [:reason]
## Sets various flags on a channel.
## """
## # TODO: Implement cmd_cset
## pass
Switches:
quiet - don't notify the channel
## def cmd_ccharge(self):
## """
## @ccharge
Kicks a player or object from a channel you control.
## Sets the cost to transmit over a channel. Default is free.
## """
## # TODO: Implement cmd_ccharge
## pass
"""
## def cmd_cboot(self):
## """
## @cboot
key = "@cboot"
locks = "cmd: not perm(channel_banned)"
help_category = "Comms"
## Usage:
## @cboot[/quiet] <channel> = <player or object>
def func(self):
"implement the function"
## Kicks a player or object from a channel you control.
## """
## caller = self.caller
## args = self.args
## switches = self.self_switches
if not self.args or not self.rhs:
string = "Usage: @cboot[/quiet] <channel> = <player> [:reason]"
self.caller.msg(string)
return
## if not args or not "=" in args:
## caller.msg("Usage: @cboot[/quiet] <channel> = <object>")
## return
## cname, objname = args.split("=",1)
## cname, objname = cname.strip(), objname.strip()
## if not cname or not objname:
## caller.msg("You must supply both channel and object.")
## return
## try:
## channel = CommChannel.objects.get(name__iexact=cname)
## except CommChannel.DoesNotExist:
## caller.msg("Could not find channel %s." % cname)
## return
channel = find_channel(self.caller, self.lhs)
if not channel:
return
reason = ""
player = None
if ":" in self.rhs:
playername, reason = self.rhs.rsplit(":", 1)
player = self.caller.search("*%s" % playername.lstrip('*'))
if not player:
player = self.caller.search("*%s" % self.rhs.lstrip('*'))
if not player:
return
if reason:
reason = " (reason: %s)" % reason
if not channel.access(self.caller, "control"):
string = "You don't control this channel."
self.caller.msg(string)
return
if not PlayerChannelConnection.objects.has_connection(player, channel):
string = "Player %s is not connected to channel %s." % (player.key, channel.key)
self.caller.msg(string)
return
if not "quiet" in self.switches:
string = "%s boots %s from channel.%s" % (self.caller, player.key, reason)
channel.msg(string)
# find all player's nicks linked to this channel and delete them
for nick in [nick for nick in player.character.nicks.get(nick_type="channel")
if nick.db_real.lower() == channel.key]:
nick.delete()
# disconnect player
channel.disconnect_from(player)
## #do we have power over this channel?
## if not channel.controlled_by(caller) or caller.has_perm("channels.channel_admin"):
## caller.msg("You don't have that power in channel '%s'." % cname)
## return
class CmdCemit(MuxCommand):
"""
@cemit - send a message to channel
## #mux specification requires an * before player objects.
## player_boot = False
## if objname[0] == '*':
## player_boot = True
## objname = objname[1:]
## bootobj = Object.objects.player_name_search(objname)
## if not bootobj:
## caller.msg("Object '%s' not found." % objname)
## return
## if bootobj.is_player() and not player_boot:
## caller.msg("To boot players you need to start their name with an '*'. ")
## return
Usage:
@cemit[/switches] <channel> = <message>
## #check so that this object really is on the channel in the first place
## membership = bootobj.channel_membership_set.filter(channel__name__iexact=cname)
## if not membership:
## caller.msg("'%s' is not on channel '%s'." % (objname,cname))
## return
Switches:
noheader - don't show the [channel] header before the message
sendername - attach the sender's name before the message
quiet - don't echo the message back to sender
## #announce to channel
## if not 'quiet' in switches:
## comsys.send_cmessage(cname, "%s boots %s from channel." % \
## (caller.get_name(show_dbref=False), objname))
Allows the user to broadcast a message over a channel as long as
they control it. It does not show the user's name unless they
provide the /sendername switch.
## #all is set, boot the object by removing all its aliases from the channel.
## for mship in membership:
## comsys.plr_del_channel(bootobj, mship.user_alias)
"""
## GLOBAL_CMD_TABLE.add_self("@cboot", cmd_cboot, help_category="Comms")
key = "@cemit"
aliases = ["@cmsg"]
locks = "cmd: not perm(channel_banned)"
help_category = "Comms"
def func(self):
"Implement function"
## def cmd_cemit(self):
## """
## @cemit - send a message to channel
if not self.args or not self.rhs:
string = "Usage: @cemit[/switches] <channel> = <message>"
self.caller.msg(string)
return
channel = find_channel(self.caller, self.lhs)
if not channel:
return
if not channel.access(self.caller, "control"):
string = "You don't control this channel."
self.caller.msg(string)
return
message = self.rhs
if "sendername" in self.switches:
message = "%s: %s" % (self.caller.key, message)
if not "noheader" in self.switches:
message = "[%s] %s" % (channel.key, message)
channel.msg(message)
if not "quiet" in self.switches:
string = "Sent to channel %s: %s" % (channel.key, message)
self.caller.msg(string)
## Usage:
## @cemit <channel>=<message>
## @cemit/noheader <channel>=<message>
## @cemit/sendername <channel>=<message>
class CmdCWho(MuxCommand):
"""
@cwho
## Allows the user to send a message over a channel as long as
## they own or control it. It does not show the user's name unless they
## provide the /sendername switch.
Usage:
@cwho <channel>
## [[channel_selfs]]
List who is connected to a given channel you have access to.
"""
key = "@cwho"
locks = "cmd: not perm(channel_banned)"
help_category = "Comms"
## Useful channel selfs
## (see their help pages for detailed help and options)
def func(self):
"implement function"
## - Listing channels
## clist - show all channels available to you
## comlist - show channels you listen to
if not self.args:
string = "Usage: @cwho <channel>"
self.caller.msg(string)
return
## - Joining/parting channels
## addcom - add your alias for a channel
## delcom - remove alias for channel
## (leave channel if no more aliases)
## allcom - view, on/off or remove all your channels
## clearcom - removes all channels
## - Other
## who - list who's online
## <chanalias> off - silence channel temporarily
## <chanalias> on - turn silenced channel back on
## """
## caller = self.caller
## if not self.args:
## caller.msg("@cemit[/switches] <channel> = <message>")
## return
## eq_args = self.args.split('=', 1)
## if len(eq_args) != 2:
## caller.msg("You must provide a channel name and a message to emit.")
## return
## cname = eq_args[0].strip()
## cmessage = eq_args[1].strip()
## final_cmessage = cmessage
## if len(cname) == 0:
## caller.msg("You must provide a channel name to emit to.")
## return
## if len(cmessage) == 0:
## caller.msg("You must provide a message to emit.")
## return
## name_matches = comsys.cname_search(cname, exact=True)
## if name_matches:
## cname_parsed = name_matches[0].get_name()
## else:
## caller.msg("Could not find channel %s." % (cname,))
## return
## # If this is False, don't show the channel header before
## # the message. For example: [Public] Woohoo!
## show_channel_header = True
## if "noheader" in self.self_switches:
## if not caller.has_perm("objects.emit_commchannel"):
## caller.msg(defines_global.NOPERMS_MSG)
## return
## final_cmessage = cmessage
## show_channel_header = False
## else:
## if "sendername" in self.self_switches:
## if not comsys.plr_has_channel(self.session, cname_parsed,
## return_muted=False):
## caller.msg("You must be on %s to do that." % (cname_parsed,))
## return
## final_cmessage = "%s: %s" % (caller.get_name(show_dbref=False),
## cmessage)
## else:
## if not caller.has_perm("objects.emit_commchannel"):
## caller.msg(defines_global.NOPERMS_MSG)
## return
## final_cmessage = cmessage
## if not "quiet" in self.self_switches:
## caller.msg("Sent - %s" % (name_matches[0],))
## comsys.send_cmessage(cname_parsed, final_cmessage,
## show_header=show_channel_header)
## #pipe to external channels (IRC, IMC) eventually mapped to this channel
## comsys.send_cexternal(cname_parsed, cmessage, caller=caller)
## GLOBAL_CMD_TABLE.add_self("@cemit", cmd_cemit,priv_tuple=("channels.emit_commchannel",),
## help_category="Comms")
## def cmd_cwho(self):
## """
## @cwho
## Usage:
## @cwho channel[/all]
## Displays the name, status and object type for a given channel.
## Adding /all after the channel name will list disconnected players
## as well.
## """
## session = self.session
## caller = self.caller
## if not self.args:
## cmd_clist(self)
## caller.msg("Usage: @cwho <channel>[/all]")
## return
## channel_name = self.args
## if channel_name.strip() == '':
## caller.msg("You must specify a channel name.")
## return
## name_matches = comsys.cname_search(channel_name, exact=True)
## if name_matches:
## # Check to make sure the user has permission to use @cwho.
## is_channel_admin = caller.has_perm("objects.channel_admin")
## is_controlled_by_plr = name_matches[0].controlled_by(caller)
## if is_controlled_by_plr or is_channel_admin:
## comsys.msg_cwho(caller, channel_name)
## else:
## caller.msg("Permission denied.")
## return
## else:
## caller.msg("No channel with that name was found.")
## return
## GLOBAL_CMD_TABLE.add_self("@cwho", cmd_cwho, help_category="Comms")
channel = find_channel(self.caller, self.lhs)
if not channel:
return
if not channel.access(self.caller, "listen"):
string = "You can't access this channel."
self.caller.msg(string)
string = "\n{CChannel subscriptions{n"
string += "\n{w%s:{n\n" % channel.key
conns = PlayerChannelConnection.objects.get_all_connections(channel)
if conns:
string += " " + ", ".join([conn.player.key for conn in conns])
else:
string += " <None>"
self.caller.msg(string.strip())
class CmdChannelCreate(MuxCommand):
"""
@ -583,47 +506,50 @@ class CmdChannelCreate(MuxCommand):
caller.msg("Created channel %s and connected to it." % new_chan.key)
## def cmd_cchown(self):
## """
## @cchown
class CmdCset(MuxCommand):
"""
@cset - changes channel access restrictions
## Usage:
## @cchown <channel> = <player>
Usage:
@cset <channel> [= <lockstring>]
## Changes the owner of a channel.
## """
## caller = self.caller
## args = self.args
## if not args or "=" not in args:
## caller.msg("Usage: @cchown <channel> = <player>")
## return
## cname, pname = args.split("=",1)
## cname, pname = cname.strip(), pname.strip()
## #locate channel
## try:
## channel = CommChannel.objects.get(name__iexact=cname)
## except CommChannel.DoesNotExist:
## caller.msg("Channel '%s' not found." % cname)
## return
## #check so we have ownership to give away.
## if not channel.controlled_by(caller) and not caller.has_perm("channels.channel_admin"):
## caller.msg("You don't control this channel.")
## return
## #find the new owner
## new_owner = Object.objects.player_name_search(pname)
## if not new_owner:
## caller.msg("New owner '%s' not found." % pname)
## return
## old_owner = channel.get_owner()
## old_pname = old_owner.get_name(show_dbref=False)
## if old_owner == new_owner:
## caller.msg("Owner unchanged.")
## return
## #all is set, change owner
## channel.set_owner(new_owner)
## caller.msg("Owner of %s changed from %s to %s." % (cname, old_pname, pname))
## new_owner.msg("%s transfered ownership of channel '%s' to you." % (old_pname, cname))
## GLOBAL_CMD_TABLE.add_self("@cchown", cmd_cchown, help_category="Comms")
Changes the lock access restrictions of a channel. If no
lockstring was given, view the current lock definitions.
"""
key = "@cset"
locks = "cmd:not perm(channel_banned)"
aliases = ["@cclock"]
help_category = "Comms"
def func(self):
"run the function"
if not self.args:
string = "Usage: @cset channel [= lockstring]"
self.caller.msg(string)
return
channel = find_channel(self.caller, self.lhs)
if not channel:
return
if not self.rhs:
# no =, so just view the current locks
string = "Current locks on %s:" % channel.key
string = "%s\n %s" % (string, channel.locks)
self.caller.msg(string)
return
# we want to add/change a lock.
if not channel.access(self.caller, "control"):
string = "You don't control this channel."
self.caller.msg(string)
return
# Try to add the lock
channel.locks.add(self.rhs)
string = "Lock(s) applied. "
string += "Current locks on %s:" % channel.key
string = "%s\n %s" % (string, channel.locks)
self.caller.msg(string)
class CmdCdesc(MuxCommand):

View file

@ -213,10 +213,24 @@ class CmdInventory(MuxCommand):
locks = "cmd:all()"
def func(self):
"hook function"
"check inventory"
items = self.caller.contents
if not items:
string = "You are not carrying anything."
else:
# format item list into nice collumns
cols = [[],[]]
for item in items:
cols[0].append(item.name)
desc = utils.crop(item.db.desc)
if not desc:
desc = ""
cols[1].append(desc)
# auto-format the columns to make them evenly wide
ftable = utils.format_table(cols)
string = "You are carrying:"
for item in self.caller.contents:
string += "\n %s" % item.name
for row in ftable:
string += "\n " + "{C%s{n - %s" % (row[0], row[1])
self.caller.msg(string)
class CmdGet(MuxCommand):
@ -552,8 +566,16 @@ class CmdAccess(MuxCommand):
hierarchy_full = settings.PERMISSION_HIERARCHY
string = "\n{wPermission Hierarchy{n (climbing):\n %s" % ", ".join(hierarchy_full)
hierarchy = [p.lower() for p in hierarchy_full]
if self.caller.player.is_superuser:
cperms = "<Superuser>"
pperms = "<Superuser>"
else:
cperms = ", ".join(caller.permissions)
pperms = ", ".join(caller.player.permissions)
string += "\n{wYour access{n:"
string += "\nCharacter %s: %s" % (caller.key, ", ".join(caller.permissions))
string += "\nCharacter {c%s{n: %s" % (caller.key, cperms)
if hasattr(caller, 'player'):
string += "\nPlayer %s: %s" % (caller.player.key, ", ".join(caller.player.permissions))
string += "\nPlayer {c%s{n: %s" % (caller.player.key, pperms)
caller.msg(string)

View file

@ -270,14 +270,14 @@ class CmdObjects(MuxCommand):
nplayers = PlayerDB.objects.count()
nobjs = ObjectDB.objects.count()
base_typeclass = settings.BASE_CHARACTER_TYPECLASS
nchars = ObjectDB.objects.filter(db_typeclass_path=base_typeclass).count()
nrooms = ObjectDB.objects.filter(db_location__isnull=True).exclude(db_typeclass_path=base_typeclass).count()
base_char_typeclass = settings.BASE_CHARACTER_TYPECLASS
nchars = ObjectDB.objects.filter(db_typeclass_path=base_char_typeclass).count()
nrooms = ObjectDB.objects.filter(db_location__isnull=True).exclude(db_typeclass_path=base_char_typeclass).count()
nexits = ObjectDB.objects.filter(db_location__isnull=False, db_destination__isnull=False).count()
string += "\n{wPlayers:{n %i" % nplayers
string += "\n{wObjects:{n %i" % nobjs
string += "\n{w Characters (base type):{n %i" % nchars
string += "\n{w Characters (BASE_CHARACTER_TYPECLASS):{n %i" % nchars
string += "\n{w Rooms (location==None):{n %i" % nrooms
string += "\n{w Exits (destination!=None):{n %i" % nexits
string += "\n{w Other:{n %i\n" % (nobjs - nchars - nrooms - nexits)
@ -579,8 +579,6 @@ class CmdServerLoad(MuxCommand):
caller.msg(string)
#TODO - expand @ps as we add irc/imc2 support.
class CmdPs(MuxCommand):
"""
list processes

View file

@ -1,101 +0,0 @@
"""
This defines some test commands for use while testing the MUD and its components.
"""
from django.conf import settings
from django.db import IntegrityError
from src.comms.models import Msg
from src.utils import create, debug, utils
from src.commands.default.muxcommand import MuxCommand
from src.commands import cmdsethandler
# Test permissions
class CmdTest(MuxCommand):
"""
test the command system
Usage:
@test <any argument or switch>
This command will echo back all argument or switches
given to it, showcasing the muxcommand style.
"""
key = "@test"
aliases = ["@te", "@test all"]
help_category = "Utils"
locks = "cmd:perm(Wizards)"
# the muxcommand class itself handles the display
# so we just defer to it by not adding any function.
def func(self):
def test():
li = []
for l in range(10000):
li.append(l)
self.caller.msg(li[-1])
return "This is the return text"
#print 1/0
def succ(f):
self.caller.msg("This is called after successful completion. Return value: %s" % f)
def err(e):
self.caller.msg("An error was encountered... %s" % e)
#self.caller.msg("printed before call to sync run ...")
#test()
#self.caller.msg("after after call to sync run...")
self.caller.msg("printed before call to async run ...")
utils.run_async(test, at_return=succ, at_err=err)
self.caller.msg("printed after call to async run ...")
#cmdsetname = "game.gamesrc.commands.default.cmdset_default.DefaultCmdSet"
#self.caller.msg(cmdsethandler.CACHED_CMDSETS)
#cmdsethandler.import_cmdset(cmdsetname, self, self)
#self.caller.msg("Imported %s" % cmdsetname)
#self.caller.msg(cmdsethandler.CACHED_CMDSETS)
class TestCom(MuxCommand):
"""
Test the command system
Usage:
@testcom/create/list [channel]
"""
key = "@testcom"
locks = "cmd:perm(Wizards)"
help_category = "Utils"
def func(self):
"Run the test program"
caller = self.caller
if 'create' in self.switches:
if self.args:
chankey = self.args
try:
channel = create.create_channel(chankey)
except IntegrityError:
caller.msg("Channel '%s' already exists." % chankey)
return
channel.connect_to(caller)
caller.msg("Created new channel %s" % chankey)
msgobj = create.create_message(caller.player,
"First post to new channel!")
channel.msg(msgobj)
return
elif 'list' in self.switches:
msgresults = Msg.objects.get_messages_by_sender(caller)
string = "\n".join(["%s %s: %s" % (msg.date_sent,
[str(chan.key) for chan in msg.channels.all()],
msg.message)
for msg in msgresults])
caller.msg(string)
return
caller.msg("Usage: @testcom/create channel")

View file

@ -10,7 +10,6 @@ import datetime
import random
from twisted.internet import threads
from django.conf import settings
from src.utils import ansi
ENCODINGS = settings.ENCODINGS
@ -32,16 +31,33 @@ def is_iter(iterable):
# except TypeError:
# return False
def fill(text, width=78):
def fill(text, width=78, indent=0):
"""
Safely wrap text to a certain number of characters.
text: (str) The text to wrap.
width: (int) The number of characters to wrap to.
indent: (int) How much to indent new lines (the first line
will not be indented)
"""
if not text:
return ""
return textwrap.fill(str(text), width)
indent = " " * indent
return textwrap.fill(str(text), width, subsequent_indent=indent)
def crop(text, width=78, suffix="[...]"):
"""
Crop text to a certain width, adding suffix to show the line
continues. Cropping will be done so that the suffix will also fit
within the given width.
"""
ltext = len(str(text))
if ltext <= width:
return text
else:
lsuffix = len(suffix)
return text[:width-lsuffix] + suffix
def dedent(text):
"""
@ -353,8 +369,7 @@ def format_table(table, extra_space=1):
if not table:
return [[]]
max_widths = [max([len(str(val))
for val in col]) for col in table]
max_widths = [max([len(str(val)) for val in col]) for col in table]
ftable = []
for irow in range(len(table[0])):
ftable.append([str(col[irow]).ljust(max_widths[icol]) + " " * extra_space