"""Implements aliases, which run code when the user's input matches against a certain pattern. """ from pymudclient.matchers import BindingPlaceholder, NonbindingPlaceholder, \ ProtoMatcher, make_decorator, BaseMatchingRealm import re class Alias(ProtoMatcher): """Matches on the user's input.""" def match(self, line): """Check to see if the line matches against our criteria.""" return list(re.finditer(self.regex, line)) binding_alias = make_decorator(Alias, BindingPlaceholder,True) non_binding_alias = make_decorator(Alias, NonbindingPlaceholder,True) class AliasMatchingRealm(BaseMatchingRealm): """Represents the context that an Alias is matched in. This has several flags and assorted pieces of information that aliases can fiddle with: .echo is whether this line will be echoed to screen or not. The client will only echo lines to screen that are also being sent; if it is not being sent, it will not be echoed. .send_to_mud is whether the input line should be sent to the MUD after it has been through all the aliases. The default is True. These attributes are not settable by aliases:
def match(self, metaline): """Test to see if the trigger's regex matches.""" if self.regex is not None: if isinstance(self.regex, list): for r in self.regex: if re.match(r, metaline.line): return re.finditer(r, metaline.line) return [] else: return re.finditer(self.regex, metaline.line) else: return [] binding_trigger = make_decorator(RegexTrigger, BindingPlaceholder,True) non_binding_trigger = make_decorator(RegexTrigger, NonbindingPlaceholder,True) class LineAlterer(object): """Caches the changes made to a Metaline so triggers don't step on each others' feet. """ def __init__(self): self._changes = deque() def delete(self, start, end): """Delete a span of text.""" self._changes.append(('delete', start, end)) def insert(self, start, text):
"""Default, do-nothing function.""" pass def __call__(self, gmcp_pair, realm): realm.trace_thunk(lambda: "%s matched!" % self) try: gmcp_type,gmcp_data=gmcp_pair if gmcp_type==self.tag: self.func(gmcp_data, realm) except Exception: #don't catch KeyboardInterrupt etc traceback.print_exc() def __str__(self): args = [type(self).__name__] #make it do the right thing for both strings and compiled patterns. if isinstance(self.tag, basestring): args.append(self.tag) else: args.append('(inactive)') #scrape our function's name, if it's interesting if self.func is not None and self.func.func_name != 'func': args.append(self.func.func_name) args.append('sequence = %d' % self.sequence) return '<%s>' % ' '.join(args) binding_gmcp_event = make_decorator(GmcpEvent, BindingPlaceholder,False) non_binding_gmcp_event = make_decorator(GmcpEvent, NonbindingPlaceholder, False)