From 089235e2ec3fbba260ee24b27dc3edeae07e2c55 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sun, 22 May 2016 12:40:02 +0200 Subject: [PATCH] Fixed the ajax websocket send of prompts, which should resolve #973. --- evennia/server/portal/webclient.py | 3 +- evennia/server/portal/webclient_ajax.py | 43 ++++++++++++++++++------- evennia/utils/text2html.py | 11 +++++++ 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/evennia/server/portal/webclient.py b/evennia/server/portal/webclient.py index f780e6ed54..967c889c24 100644 --- a/evennia/server/portal/webclient.py +++ b/evennia/server/portal/webclient.py @@ -156,6 +156,7 @@ class WebSocketClient(Protocol, Session): return else: return + flags = self.protocol_flags text = to_str(text, force_string=True) @@ -199,5 +200,5 @@ class WebSocketClient(Protocol, Session): """ if not cmdname == "options": - print "websocket.send_default", cmdname, args, kwargs + #print "websocket.send_default", cmdname, args, kwargs session.sendLine(json.dumps([cmdname, args, kwargs])) diff --git a/evennia/server/portal/webclient_ajax.py b/evennia/server/portal/webclient_ajax.py index f894ed6206..dceab1c5ab 100644 --- a/evennia/server/portal/webclient_ajax.py +++ b/evennia/server/portal/webclient_ajax.py @@ -17,6 +17,7 @@ http://localhost:8000/webclient.) to sessions connected over the webclient. """ import json +import re from time import time from hashlib import md5 @@ -25,10 +26,12 @@ from twisted.internet.task import LoopingCall from django.utils.functional import Promise from django.utils.encoding import force_unicode from django.conf import settings +from evennia.utils.ansi import parse_ansi from evennia.utils import utils from evennia.utils.text2html import parse_html from evennia.server import session +_RE_SCREENREADER_REGEX = re.compile(r"%s" % settings.SCREENREADER_REGEX_STRIP, re.DOTALL + re.MULTILINE) _SERVERNAME = settings.SERVERNAME _KEEPALIVE = 30 # how often to check keepalive @@ -319,35 +322,53 @@ class WebClientSession(session.Session): def send_text(self, *args, **kwargs): """ - Send text data. + Send text data. This will pre-process the text for + color-replacement, conversion to html etc. Args: - text (str): The first argument is always the text string to send. No other arguments - are considered. + text (str): Text to send. + Kwargs: - raw (bool): No parsing at all (leave ansi-to-html markers unparsed). - nomarkup (bool): Clean out all ansi/html markers and tokens. + options (dict): Options-dict with the following keys understood: + - raw (bool): No parsing at all (leave ansi-to-html markers unparsed). + - nomarkup (bool): Clean out all ansi/html markers and tokens. + - screenreader (bool): Use Screenreader mode. + - send_prompt (bool): Send a prompt with parsed html """ - # string handling is similar to telnet - if args: args = list(args) text = args[0] if text is None: return - text = utils.to_str(text, force_string=True) + else: + return - options = kwargs.get("options", {}) + flags = self.protocol_flags + text = utils.to_str(text, force_string=True) + + options = kwargs.pop("options", {}) raw = options.get("raw", False) nomarkup = options.get("nomarkup", False) + screenreader = options.get("screenreader", flags.get("SCREENREADER", False)) + prompt = options.get("send_prompt", False) + if screenreader: + # screenreader mode cleans up output + text = parse_ansi(text, strip_ansi=True, xterm256=False, mxp=False) + text = _RE_SCREENREADER_REGEX.sub("", text) + cmd = "prompt" if prompt else "text" if raw: args[0] = text else: args[0] = parse_html(text, strip_ansi=nomarkup) - self.client.lineSend(self.suid, ["text", args, kwargs]) + # send to client on required form [cmdname, args, kwargs] + self.client.lineSend(self.suid, [cmd, args, kwargs]) + + def send_prompt(self, *args, **kwargs): + kwargs["options"].update({"send_prompt": True}) + self.send_text(*args, **kwargs) def send_default(self, cmdname, *args, **kwargs): """ @@ -364,5 +385,5 @@ class WebClientSession(session.Session): """ if not cmdname == "options": - print "ajax.send_default", cmdname, args, kwargs + #print "ajax.send_default", cmdname, args, kwargs self.client.lineSend(self.suid, [cmdname, args, kwargs]) diff --git a/evennia/utils/text2html.py b/evennia/utils/text2html.py index 6a6e38afda..020b808fc8 100644 --- a/evennia/utils/text2html.py +++ b/evennia/utils/text2html.py @@ -20,6 +20,8 @@ from .ansi import * XTERM256_FG = "\033[38;5;%sm" XTERM256_BG = "\033[48;5;%sm" +_RE_XTERM256 = re.compile("(\033\[(?:38|48);5;[0-9]{3}m)") + class TextToHTMLparser(object): """ This class describes a parser for converting from ANSI to html. @@ -87,8 +89,13 @@ class TextToHTMLparser(object): bgstop = "|".join(co[1] for co in colorback + bgstop + [("", "$")]) # pre-compile regexes + #re_fgs = "|".join(["%s.*?(?=%s)" % (code, fgstop) for cname, code in colorcodes]) + #re_bgs = "|".join(["%s.*?(?=%s)" % (code, bgstop) for cname, code in colorback]) + #re_clrs = re_fgs + "|" + re_bgs + re_fgs = [(cname, re.compile("(?:%s)(.*?)(?=%s)" % (code, fgstop))) for cname, code in colorcodes] re_bgs = [(cname, re.compile("(?:%s)(.*?)(?=%s)" % (code, bgstop))) for cname, code in colorback] + re_normal = re.compile(normal.replace("[", r"\[")) re_hilite = re.compile("(?:%s)(.*)(?=%s)" % (hilite.replace("[", r"\["), fgstop)) re_uline = re.compile("(?:%s)(.*?)(?=%s)" % (ANSI_UNDERLINE.replace("[", r"\["), fgstop)) @@ -96,6 +103,10 @@ class TextToHTMLparser(object): re_url = re.compile(r'((?:ftp|www|https?)\W+(?:(?!\.(?:\s|$)|&\w+;)[^"\',;$*^\\(){}<>\[\]\s])+)(\.(?:\s|$)|&\w+;|)') re_mxplink = re.compile(r'\|lc(.*?)\|lt(.*?)\|le', re.DOTALL) + def _sub_clr(self, colormatch): + colormatch.group() + return + def re_color(self, text): """ Replace ansi colors with html color class names. Let the