Add MXP support for anchor tags

This commit is contained in:
fariparedes 2021-06-18 14:26:36 -04:00
parent 0bd7860974
commit 7358758987
6 changed files with 35 additions and 5 deletions

View file

@ -66,6 +66,7 @@ Up requirements to Django 3.2+
into a more consistent structure for overriding. Expanded webpage documentation considerably. into a more consistent structure for overriding. Expanded webpage documentation considerably.
- REST API list-view was shortened (#2401). New CSS/HTML. Add ReDoc for API autodoc page. - REST API list-view was shortened (#2401). New CSS/HTML. Add ReDoc for API autodoc page.
- Update and fix dummyrunner with cleaner code and setup. - Update and fix dummyrunner with cleaner code and setup.
- Added an MXP anchor tag in addition to the command tag
### Evennia 0.9.5 (2019-2020) ### Evennia 0.9.5 (2019-2020)

View file

@ -1,11 +1,12 @@
## Clickable links ## Clickable links
Evennia supports clickable links for clients that supports it. This marks certain text so it can be Evennia supports clickable links for clients that supports it. This marks certain text so it can be
clicked by a mouse and trigger a given Evennia command. To support clickable links, Evennia requires clicked by a mouse and either trigger a given Evennia command, or open a URL in an external web
the webclient or an third-party telnet client with [MXP](http://www.zuggsoft.com/zmud/mxp.htm) browser. To support clickable links, Evennia requires the webclient or an third-party telnet client
support (*Note: Evennia only supports clickable links, no other MXP features*). with [MXP](http://www.zuggsoft.com/zmud/mxp.htm) support (*Note: Evennia only supports clickable links, no other MXP features*).
- `|lc` to start the link, by defining the command to execute. - `|lc` to start the link, by defining the command to execute.
- `|lu` to start the link, by defining the URL to open.
- `|lt` to continue with the text to show to the user (the link text). - `|lt` to continue with the text to show to the user (the link text).
- `|le` to end the link text and the link definition. - `|le` to end the link text and the link definition.

View file

@ -16,12 +16,14 @@ http://www.gammon.com.au/mushclient/addingservermxp.htm
import re import re
LINKS_SUB = re.compile(r"\|lc(.*?)\|lt(.*?)\|le", re.DOTALL) LINKS_SUB = re.compile(r"\|lc(.*?)\|lt(.*?)\|le", re.DOTALL)
URL_SUB = re.compile(r"\|lu(.*?)\|lt(.*?)\|le", re.DOTALL)
# MXP Telnet option # MXP Telnet option
MXP = bytes([91]) # b"\x5b" MXP = bytes([91]) # b"\x5b"
MXP_TEMPSECURE = "\x1B[4z" MXP_TEMPSECURE = "\x1B[4z"
MXP_SEND = MXP_TEMPSECURE + '<SEND HREF="\\1">' + "\\2" + MXP_TEMPSECURE + "</SEND>" MXP_SEND = MXP_TEMPSECURE + '<SEND HREF="\\1">' + "\\2" + MXP_TEMPSECURE + "</SEND>"
MXP_URL = MXP_TEMPSECURE + '<A HREF="\\1">' + "\\2" + MXP_TEMPSECURE + "</A>"
def mxp_parse(text): def mxp_parse(text):
@ -38,6 +40,7 @@ def mxp_parse(text):
text = text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;") text = text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
text = LINKS_SUB.sub(MXP_SEND, text) text = LINKS_SUB.sub(MXP_SEND, text)
text = URL_SUB.sub(MXP_URL, text)
return text return text

View file

@ -223,6 +223,7 @@ class ANSIParser(object):
ansi_xterm256_bright_bg_map += settings.COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP ansi_xterm256_bright_bg_map += settings.COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP
mxp_re = r"\|lc(.*?)\|lt(.*?)\|le" mxp_re = r"\|lc(.*?)\|lt(.*?)\|le"
mxp_url_re = r"\|lu(.*?)\|lt(.*?)\|le"
# prepare regex matching # prepare regex matching
brightbg_sub = re.compile( brightbg_sub = re.compile(
@ -237,6 +238,7 @@ class ANSIParser(object):
# xterm256_sub = re.compile(r"|".join([tup[0] for tup in xterm256_map]), re.DOTALL) # xterm256_sub = re.compile(r"|".join([tup[0] for tup in xterm256_map]), re.DOTALL)
ansi_sub = re.compile(r"|".join([re.escape(tup[0]) for tup in ansi_map]), re.DOTALL) ansi_sub = re.compile(r"|".join([re.escape(tup[0]) for tup in ansi_map]), re.DOTALL)
mxp_sub = re.compile(mxp_re, re.DOTALL) mxp_sub = re.compile(mxp_re, re.DOTALL)
mxp_url_sub = re.compile(mxp_url_re, re.DOTALL)
# used by regex replacer to correctly map ansi sequences # used by regex replacer to correctly map ansi sequences
ansi_map_dict = dict(ansi_map) ansi_map_dict = dict(ansi_map)
@ -424,7 +426,9 @@ class ANSIParser(object):
string (str): The processed string. string (str): The processed string.
""" """
return self.mxp_sub.sub(r"\2", string) string = self.mxp_sub.sub(r"\2", string)
string = self.mxp_url_sub.sub(r"\2", string)
return string
def parse_ansi(self, string, strip_ansi=False, xterm256=False, mxp=False): def parse_ansi(self, string, strip_ansi=False, xterm256=False, mxp=False):
""" """

View file

@ -145,13 +145,17 @@ class ANSIStringTestCase(TestCase):
""" """
mxp1 = "|lclook|ltat|le" mxp1 = "|lclook|ltat|le"
mxp2 = "Start to |lclook here|ltclick somewhere here|le first" mxp2 = "Start to |lclook here|ltclick somewhere here|le first"
mxp3 = "Check out |luhttps://www.example.com|ltmy website|le!"
self.assertEqual(15, len(ANSIString(mxp1))) self.assertEqual(15, len(ANSIString(mxp1)))
self.assertEqual(53, len(ANSIString(mxp2))) self.assertEqual(53, len(ANSIString(mxp2)))
self.assertEqual(53, len(ANSIString(mxp3)))
# These would indicate an issue with the tables. # These would indicate an issue with the tables.
self.assertEqual(len(ANSIString(mxp1)), len(ANSIString(mxp1).split("\n")[0])) self.assertEqual(len(ANSIString(mxp1)), len(ANSIString(mxp1).split("\n")[0]))
self.assertEqual(len(ANSIString(mxp2)), len(ANSIString(mxp2).split("\n")[0])) self.assertEqual(len(ANSIString(mxp2)), len(ANSIString(mxp2).split("\n")[0]))
self.assertEqual(len(ANSIString(mxp3)), len(ANSIString(mxp3).split("\n")[0]))
self.assertEqual(mxp1, ANSIString(mxp1)) self.assertEqual(mxp1, ANSIString(mxp1))
self.assertEqual(mxp2, str(ANSIString(mxp2))) self.assertEqual(mxp2, str(ANSIString(mxp2)))
self.assertEqual(mxp3, str(ANSIString(mxp3)))
def test_add(self): def test_add(self):
""" """

View file

@ -103,9 +103,10 @@ class TextToHTMLparser(object):
) )
re_dblspace = re.compile(r" {2,}", re.M) re_dblspace = re.compile(r" {2,}", re.M)
re_url = re.compile( re_url = re.compile(
r'((?:ftp|www|https?)\W+(?:(?!\.(?:\s|$)|&\w+;)[^"\',;$*^\\(){}<>\[\]\s])+)(\.(?:\s|$)|&\w+;|)' r'(?<!=")((?:ftp|www|https?)\W+(?:(?!\.(?:\s|$)|&\w+;)[^"\',;$*^\\(){}<>\[\]\s])+)(\.(?:\s|$)|&\w+;|)'
) )
re_mxplink = re.compile(r"\|lc(.*?)\|lt(.*?)\|le", re.DOTALL) re_mxplink = re.compile(r"\|lc(.*?)\|lt(.*?)\|le", re.DOTALL)
re_mxpurl = re.compile(r"\|lu(.*?)\|lt(.*?)\|le", re.DOTALL)
def _sub_bgfg(self, colormatch): def _sub_bgfg(self, colormatch):
# print("colormatch.groups()", colormatch.groups()) # print("colormatch.groups()", colormatch.groups())
@ -290,6 +291,21 @@ class TextToHTMLparser(object):
) )
return val return val
def sub_mxp_urls(self, match):
"""
Helper method to be passed to re.sub,
replaces MXP links with HTML code.
Args:
match (re.Matchobject): Match for substitution.
Returns:
text (str): Processed text.
"""
url, text = [grp.replace('"', "\\&quot;") for grp in match.groups()]
val = (
r"""<a id="mxplink" href="{url}" target="_blank">{text}</a>""".format(url=url, text=text)
)
return val
def sub_text(self, match): def sub_text(self, match):
""" """
Helper method to be passed to re.sub, Helper method to be passed to re.sub,
@ -337,6 +353,7 @@ class TextToHTMLparser(object):
# convert all ansi to html # convert all ansi to html
result = re.sub(self.re_string, self.sub_text, text) result = re.sub(self.re_string, self.sub_text, text)
result = re.sub(self.re_mxplink, self.sub_mxp_links, result) result = re.sub(self.re_mxplink, self.sub_mxp_links, result)
result = re.sub(self.re_mxpurl, self.sub_mxp_urls, result)
result = self.re_color(result) result = self.re_color(result)
result = self.re_bold(result) result = self.re_bold(result)
result = self.re_underline(result) result = self.re_underline(result)