plugin: handle aliases for commands

This commit is contained in:
dece 2020-11-02 17:41:47 +01:00
parent d85d5e054f
commit 3748312c41
5 changed files with 59 additions and 24 deletions

View file

@ -41,7 +41,7 @@ Missing features
- [x] Wikipedia: find definition, get random page - [x] Wikipedia: find definition, get random page
- [ ] Wolframalpha - [ ] Wolframalpha
- [ ] Youtube: parsing for title, requests for channel or video - [ ] Youtube: parsing for title, requests for channel or video
- [ ] Command aliases - [x] Command aliases
- [ ] Question aliases - [ ] Question aliases
- [x] Sleep - [x] Sleep
- [ ] Various macros: - [ ] Various macros:

View file

@ -129,33 +129,59 @@ class Plugin:
return False return False
# Is it a valid command? # Is it a valid command?
command = self.parse_command(message, no_content=no_content) parsed_command = self.__parse_command(message, no_content=no_content)
if not command: if not parsed_command:
return False return False
# Is it a command I can handle? # Is it a command I can handle?
commands = self.config.get("commands", []) available_commands = self.config.get("commands", [])
if ( aliases = self.config.get("aliases", {})
any(command.ident == c for c in commands) or for ident in available_commands:
(no_content and any(command.ident.startswith(c) for c in commands)) # Match commands differently according to no_content. If no_content
): # is True, check the parsed command (pc) raw data as a string that
self.command = command # may contain the available identifier (ai) at its beginning.
self.bot.log_d(f"Processing command from plugin {self.name}.") # If no_content is False (default), simply compare the parsed
return True # identifier with available identifiers.
if no_content:
match = lambda pc, ai: (
pc.raw == ai or pc.raw.startswith(ai + " ")
)
else:
match = lambda pc, ai: pc.ident == ai
# First case: the command identifier has been used.
if match(parsed_command, ident):
parsed_command.ident = ident
parsed_command.match = ident
self.__save_command(parsed_command)
return True
# Second case: an alias of the identifier has been used.
ident_aliases = aliases.get(ident, [])
for alias in ident_aliases:
if match(parsed_command, alias):
parsed_command.ident = ident
parsed_command.match = alias
self.__save_command(parsed_command)
return True
return False return False
def parse_command(self, message, no_content=False): def __parse_command(self, message, no_content=False):
"""Return a command ID if this message is a command.""" """Return a command ID if this message is a command.
The command raw field is always set. The ident and content fields are
not set when no_content is True. The match field is never set by this
method.
"""
words = message.split() words = message.split()
command_suffix = self.config["command_suffix"] command_suffix = self.config["command_suffix"]
if words[0].lower() in self.bot.names and words[-1] == command_suffix: if words[0].lower() in self.bot.names and words[-1] == command_suffix:
raw = " ".join(words[1:-1])
if no_content: if no_content:
ident = " ".join(words[1:-1]) ident = ""
content = "" content = ""
else: else:
ident = words[1] ident = words[1]
content = " ".join(words[2:-1]) content = " ".join(words[2:-1])
return Command(ident, content) return Command(ident, content, raw)
def __respects_handling_conditions(self, exclude_conditions=None): def __respects_handling_conditions(self, exclude_conditions=None):
"""Check if question conditions are valid.""" """Check if question conditions are valid."""
@ -172,6 +198,11 @@ class Plugin:
return False return False
return True return True
def __save_command(self, command):
"""Save command in instance for further processing by the plugin."""
self.command = command
self.bot.log_d(f"Processing command from plugin {self.name}: {command}")
def signal_failure(self, target): def signal_failure(self, target):
"""Signal a plugin failure to target.""" """Signal a plugin failure to target."""
self.bot.say(target, self.bot.config["error_message"]) self.bot.say(target, self.bot.config["error_message"])
@ -185,5 +216,11 @@ class Question:
@dataclass @dataclass
class Command: class Command:
# Identifier as set in config. Set even when an alias has been used.
ident: str ident: str
# Content of the command when it has been parsed, empty str otherwise.
content: str content: str
# Raw command content (minus name and suffix), always set.
raw: str
# Identifier matched, possibly an alias. Set only when matched.
match: str = ""

View file

@ -44,9 +44,11 @@ class MoodPlugin(Plugin):
self.bot.say(event.target, random.choice(greetings)) self.bot.say(event.target, random.choice(greetings))
def on_pubmsg(self, event): def on_pubmsg(self, event):
# Only one command: calm down.
if self.should_handle_command(event.arguments[0], no_content=True): if self.should_handle_command(event.arguments[0], no_content=True):
self.calm_down(event.target) self.calm_down(event.target)
return True return True
# Only one question: what's your mood?
if self.should_answer_question(event.arguments[0]): if self.should_answer_question(event.arguments[0]):
self.say_mood(event.target) self.say_mood(event.target)
return True return True

View file

@ -31,9 +31,8 @@ class NotesPlugin(Plugin):
return False return False
# "note down" command. # "note down" command.
command0 = self.config["commands"][0] if self.command.ident == self.config["commands"][0]:
if self.command.ident.startswith(command0): content = self.command.raw[len(self.command.match):].strip()
content = self.command.ident[len(command0):].strip()
match = self.content_re.match(content) match = self.content_re.match(content)
if not match: if not match:
return False return False
@ -59,8 +58,7 @@ class NotesPlugin(Plugin):
return True return True
# "deliver notes for me" command. # "deliver notes for me" command.
command1 = self.config["commands"][1] if self.command.ident == self.config["commands"][1]:
if self.command.ident == command1:
self.deliver_notes(event.target, event.source.nick) self.deliver_notes(event.target, event.source.nick)
return True return True

View file

@ -42,14 +42,12 @@ class SleepPlugin(Plugin):
return False return False
# "sleep" command. # "sleep" command.
command0 = self.config["commands"][0] if self.command.ident == self.config["commands"][0]:
if self.command.ident.startswith(command0):
self.fall_asleep() self.fall_asleep()
return True return True
# "wake up" command. # "wake up" command.
command1 = self.config["commands"][1] if self.command.ident == self.config["commands"][1]:
if self.command.ident.startswith(command1):
self.wake_up() self.wake_up()
return True return True