Merge pull request #2358 from fariparedes/mxp-url

Add anchor tag for MXP
This commit is contained in:
Griatch 2021-06-19 12:14:01 +02:00 committed by GitHub
commit 9bc6978e28
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.
- 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.
- Added an MXP anchor tag in addition to the command tag
### Evennia 0.9.5 (2019-2020)

View file

@ -1,11 +1,12 @@
## Clickable links
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
the webclient or an third-party telnet client with [MXP](http://www.zuggsoft.com/zmud/mxp.htm)
support (*Note: Evennia only supports clickable links, no other MXP features*).
clicked by a mouse and either trigger a given Evennia command, or open a URL in an external web
browser. To support clickable links, Evennia requires the webclient or an third-party telnet client
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.
- `|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).
- `|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
LINKS_SUB = re.compile(r"\|lc(.*?)\|lt(.*?)\|le", re.DOTALL)
URL_SUB = re.compile(r"\|lu(.*?)\|lt(.*?)\|le", re.DOTALL)
# MXP Telnet option
MXP = bytes([91]) # b"\x5b"
MXP_TEMPSECURE = "\x1B[4z"
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):
@ -38,6 +40,7 @@ def mxp_parse(text):
text = text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
text = LINKS_SUB.sub(MXP_SEND, text)
text = URL_SUB.sub(MXP_URL, 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
mxp_re = r"\|lc(.*?)\|lt(.*?)\|le"
mxp_url_re = r"\|lu(.*?)\|lt(.*?)\|le"
# prepare regex matching
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)
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_url_sub = re.compile(mxp_url_re, re.DOTALL)
# used by regex replacer to correctly map ansi sequences
ansi_map_dict = dict(ansi_map)
@ -424,7 +426,9 @@ class ANSIParser(object):
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):
"""

View file

@ -145,13 +145,17 @@ class ANSIStringTestCase(TestCase):
"""
mxp1 = "|lclook|ltat|le"
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(53, len(ANSIString(mxp2)))
self.assertEqual(53, len(ANSIString(mxp3)))
# These would indicate an issue with the tables.
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(mxp3)), len(ANSIString(mxp3).split("\n")[0]))
self.assertEqual(mxp1, ANSIString(mxp1))
self.assertEqual(mxp2, str(ANSIString(mxp2)))
self.assertEqual(mxp3, str(ANSIString(mxp3)))
def test_add(self):
"""

View file

@ -103,9 +103,10 @@ class TextToHTMLparser(object):
)
re_dblspace = re.compile(r" {2,}", re.M)
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_mxpurl = re.compile(r"\|lu(.*?)\|lt(.*?)\|le", re.DOTALL)
def _sub_bgfg(self, colormatch):
# print("colormatch.groups()", colormatch.groups())
@ -290,6 +291,21 @@ class TextToHTMLparser(object):
)
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):
"""
Helper method to be passed to re.sub,
@ -337,6 +353,7 @@ class TextToHTMLparser(object):
# convert all ansi to html
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_mxpurl, self.sub_mxp_urls, result)
result = self.re_color(result)
result = self.re_bold(result)
result = self.re_underline(result)