nemubot/modules/alias.py

281 lines
9.3 KiB
Python
Raw Normal View History

2014-08-27 23:39:31 +00:00
"""Create alias of commands"""
2015-09-09 23:40:06 +00:00
# PYTHON STUFFS #######################################################
2012-06-30 16:40:42 +00:00
import re
2014-09-30 21:51:14 +00:00
from datetime import datetime, timezone
2014-10-05 16:19:20 +00:00
import shlex
2012-06-30 16:40:42 +00:00
2015-02-11 17:12:39 +00:00
from nemubot import context
from nemubot.exception import IMException
from nemubot.hooks import hook
from nemubot.message import Command
2015-01-05 09:18:40 +00:00
from nemubot.tools.xmlparser.node import ModuleState
from more import Response
2014-11-13 01:51:49 +00:00
2015-09-09 23:40:06 +00:00
# LOADING #############################################################
2012-08-22 23:54:52 +00:00
def load(context):
"""Load this module"""
2015-02-11 17:12:39 +00:00
if not context.data.hasNode("aliases"):
context.data.addChild(ModuleState("aliases"))
context.data.getNode("aliases").setIndex("alias")
if not context.data.hasNode("variables"):
context.data.addChild(ModuleState("variables"))
context.data.getNode("variables").setIndex("name")
2012-06-30 16:40:42 +00:00
2015-09-09 23:40:06 +00:00
# MODULE CORE #########################################################
## Alias management
def list_alias(channel=None):
"""List known aliases.
Argument:
channel -- optional, if defined, return a list of aliases only defined on this channel, else alias widly defined
"""
2012-06-30 16:40:42 +00:00
2015-09-09 23:40:06 +00:00
for alias in context.data.getNode("aliases").index.values():
if (channel is None and "channel" not in alias) or (channel is not None and "channel" in alias and alias["channel"] == channel):
yield alias
def create_alias(alias, origin, channel=None, creator=None):
"""Create or erase an existing alias
"""
anode = ModuleState("alias")
anode["alias"] = alias
anode["origin"] = origin
if channel is not None:
anode["creator"] = channel
if creator is not None:
anode["creator"] = creator
context.data.getNode("aliases").addChild(anode)
context.save()
## Variables management
2014-11-13 01:51:49 +00:00
2012-08-22 23:54:52 +00:00
def get_variable(name, msg=None):
2015-09-09 23:40:06 +00:00
"""Get the value for the given variable
Arguments:
name -- The variable identifier
msg -- optional, original message where some variable can be picked
"""
if msg is not None and (name == "sender" or name == "from" or name == "nick"):
2014-10-05 16:19:20 +00:00
return msg.frm
2015-09-09 23:40:06 +00:00
elif msg is not None and (name == "chan" or name == "channel"):
2012-08-22 23:54:52 +00:00
return msg.channel
elif name == "date":
2014-09-30 21:51:14 +00:00
return datetime.now(timezone.utc).strftime("%c")
2015-02-11 17:12:39 +00:00
elif name in context.data.getNode("variables").index:
return context.data.getNode("variables").index[name]["value"]
2012-08-22 23:54:52 +00:00
else:
return ""
2014-11-13 01:51:49 +00:00
2015-09-09 23:40:06 +00:00
def list_variables(user=None):
"""List known variables.
2012-08-22 23:54:52 +00:00
2015-09-09 23:40:06 +00:00
Argument:
user -- optional, if defined, display only variable created by the given user
"""
if user is not None:
return [x for x in context.data.getNode("variables").index.values() if x["creator"] == user]
2015-07-10 22:09:43 +00:00
else:
2015-09-09 23:40:06 +00:00
return context.data.getNode("variables").index.values()
2014-11-13 01:51:49 +00:00
2015-09-09 23:40:06 +00:00
def set_variable(name, value, creator):
"""Define or erase a variable.
2014-11-13 01:51:49 +00:00
2015-09-09 23:40:06 +00:00
Arguments:
name -- The variable identifier
value -- Variable value
creator -- User who has created this variable
"""
2015-09-09 23:40:06 +00:00
var = ModuleState("variable")
var["name"] = name
var["value"] = value
var["creator"] = creator
context.data.getNode("variables").addChild(var)
context.save()
2014-11-13 01:51:49 +00:00
def replace_variables(cnts, msg=None):
2015-09-09 23:40:06 +00:00
"""Replace variables contained in the content
2014-11-13 01:51:49 +00:00
2015-09-09 23:40:06 +00:00
Arguments:
cnt -- content where search variables
msg -- optional message where pick some variables
"""
unsetCnt = list()
if not isinstance(cnts, list):
cnts = list(cnts)
resultCnt = list()
for cnt in cnts:
for res in re.findall("\\$\{(?P<name>[a-zA-Z0-9:]+)\}", cnt):
rv = re.match("([0-9]+)(:([0-9]*))?", res)
if rv is not None:
varI = int(rv.group(1)) - 1
if varI > len(msg.args):
cnt = cnt.replace("${%s}" % res, "", 1)
elif rv.group(2) is not None:
if rv.group(3) is not None and len(rv.group(3)):
varJ = int(rv.group(3)) - 1
cnt = cnt.replace("${%s}" % res, " ".join(msg.args[varI:varJ]), 1)
for v in range(varI, varJ):
unsetCnt.append(v)
else:
cnt = cnt.replace("${%s}" % res, " ".join(msg.args[varI:]), 1)
for v in range(varI, len(msg.args)):
unsetCnt.append(v)
else:
cnt = cnt.replace("${%s}" % res, msg.args[varI], 1)
unsetCnt.append(varI)
else:
cnt = cnt.replace("${%s}" % res, get_variable(res), 1)
resultCnt.append(cnt)
for u in sorted(set(unsetCnt), reverse=True):
2015-10-30 20:10:06 +00:00
msg.args.pop(u)
return resultCnt
2015-09-09 23:40:06 +00:00
# MODULE INTERFACE ####################################################
## Variables management
2015-11-02 19:19:12 +00:00
@hook.command("listvars",
2015-10-05 21:54:38 +00:00
help="list defined variables for substitution in input commands",
help_usage={
None: "List all known variables",
"USER": "List variables created by USER"})
2015-09-09 23:40:06 +00:00
def cmd_listvars(msg):
if len(msg.args):
res = list()
for user in msg.args:
2015-10-08 21:59:24 +00:00
als = [v["name"] for v in list_variables(user)]
2015-09-09 23:40:06 +00:00
if len(als) > 0:
2015-10-05 21:54:38 +00:00
res.append("%s's variables: %s" % (user, ", ".join(als)))
2015-09-09 23:40:06 +00:00
else:
2015-10-05 21:54:38 +00:00
res.append("%s didn't create variable yet." % user)
2015-09-09 23:40:06 +00:00
return Response(" ; ".join(res), channel=msg.channel)
elif len(context.data.getNode("variables").index):
2015-10-18 09:39:44 +00:00
return Response(list_variables(),
channel=msg.channel,
title="Known variables")
2015-09-09 23:40:06 +00:00
else:
2015-10-05 21:54:38 +00:00
return Response("There is currently no variable stored.", channel=msg.channel)
2015-09-09 23:40:06 +00:00
2015-11-02 19:19:12 +00:00
@hook.command("set",
2015-10-05 21:54:38 +00:00
help="Create or set variables for substitution in input commands",
help_usage={"KEY VALUE": "Define the variable named KEY and fill it with VALUE as content"})
2015-09-09 23:40:06 +00:00
def cmd_set(msg):
if len(msg.args) < 2:
raise IMException("!set take two args: the key and the value.")
2015-09-09 23:40:06 +00:00
set_variable(msg.args[0], " ".join(msg.args[1:]), msg.nick)
2015-10-08 21:59:24 +00:00
return Response("Variable $%s successfully defined." % msg.args[0],
2015-09-09 23:40:06 +00:00
channel=msg.channel)
## Alias management
2015-11-02 19:19:12 +00:00
@hook.command("listalias",
2015-10-05 21:54:38 +00:00
help="List registered aliases",
help_usage={
None: "List all registered aliases",
"USER": "List all aliases created by USER"})
2015-09-09 23:40:06 +00:00
def cmd_listalias(msg):
aliases = [a for a in list_alias(None)] + [a for a in list_alias(msg.channel)]
if len(aliases):
return Response([a["alias"] for a in aliases],
channel=msg.channel,
2015-10-18 09:39:44 +00:00
title="Known aliases")
2015-09-09 23:40:06 +00:00
return Response("There is no alias currently.", channel=msg.channel)
2015-11-02 19:19:12 +00:00
@hook.command("alias",
2015-10-05 21:54:38 +00:00
help="Display the replacement command for a given alias")
2015-09-09 23:40:06 +00:00
def cmd_alias(msg):
if not len(msg.args):
raise IMException("!alias takes as argument an alias to extend.")
2015-09-09 23:40:06 +00:00
res = list()
for alias in msg.args:
if alias[0] == "!":
alias = alias[1:]
if alias in context.data.getNode("aliases").index:
2015-10-05 21:54:38 +00:00
res.append("!%s correspond to %s" % (alias, context.data.getNode("aliases").index[alias]["origin"]))
2015-09-09 23:40:06 +00:00
else:
2015-10-05 21:54:38 +00:00
res.append("!%s is not an alias" % alias)
2015-09-09 23:40:06 +00:00
return Response(res, channel=msg.channel, nick=msg.nick)
2015-11-02 19:19:12 +00:00
@hook.command("unalias",
2015-10-05 21:54:38 +00:00
help="Remove a previously created alias")
2015-09-09 23:40:06 +00:00
def cmd_unalias(msg):
if not len(msg.args):
raise IMException("Which alias would you want to remove?")
2015-09-09 23:40:06 +00:00
res = list()
for alias in msg.args:
if alias[0] == "!" and len(alias) > 1:
alias = alias[1:]
if alias in context.data.getNode("aliases").index:
context.data.getNode("aliases").delChild(context.data.getNode("aliases").index[alias])
2015-10-05 21:54:38 +00:00
res.append(Response("%s doesn't exist anymore." % alias,
2015-09-09 23:40:06 +00:00
channel=msg.channel))
else:
2015-10-05 21:54:38 +00:00
res.append(Response("%s is not an alias" % alias,
2015-09-09 23:40:06 +00:00
channel=msg.channel))
return res
## Alias replacement
2015-11-02 19:19:12 +00:00
@hook.add("pre_Command")
def treat_alias(msg):
2015-02-11 17:12:39 +00:00
if msg.cmd in context.data.getNode("aliases").index:
txt = context.data.getNode("aliases").index[msg.cmd]["origin"]
2014-10-05 16:19:20 +00:00
# TODO: for legacy compatibility
if txt[0] == "!":
txt = txt[1:]
try:
args = shlex.split(txt)
except ValueError:
args = txt.split(' ')
2015-11-14 14:47:08 +00:00
nmsg = Command(args[0], args=replace_variables(args[1:], msg) + msg.args, kwargs=msg.kwargs, **msg.export_args())
# Avoid infinite recursion
2014-10-05 16:19:20 +00:00
if msg.cmd != nmsg.cmd:
2015-06-10 22:09:33 +00:00
# Also return origin message, if it can be treated as well
return [msg, nmsg]
2014-10-05 16:19:20 +00:00
return msg
2012-06-30 16:40:42 +00:00
2015-11-02 19:19:12 +00:00
@hook.ask()
2012-08-22 23:54:52 +00:00
def parseask(msg):
2015-10-05 21:54:38 +00:00
if re.match(".*(register|set|cr[ée]{2}|new|nouvel(le)?) alias.*", msg.text) is not None:
result = re.match(".*alias !?([^ ]+) ?(pour|for|=|:) ?(.+)$", msg.text)
2015-06-10 22:06:55 +00:00
if result.group(1) in context.data.getNode("aliases").index:
raise IMException("this alias is already defined.")
else:
2015-09-09 23:40:06 +00:00
create_alias(result.group(1),
result.group(3),
channel=msg.channel,
creator=msg.nick)
2015-10-05 21:54:38 +00:00
res = Response("New alias %s successfully registered." %
2014-11-13 01:51:49 +00:00
result.group(1), channel=msg.channel)
return res
return None