diff --git a/evennia/game_template/server/conf/inlinefunc.py b/evennia/game_template/server/conf/inlinefuncs.py
similarity index 80%
rename from evennia/game_template/server/conf/inlinefunc.py
rename to evennia/game_template/server/conf/inlinefuncs.py
index 2634e2fdee..c4edd83daf 100644
--- a/evennia/game_template/server/conf/inlinefunc.py
+++ b/evennia/game_template/server/conf/inlinefuncs.py
@@ -11,17 +11,17 @@ evennia.utils.inlinefunc.
In text, usage is straightforward:
-{funcname([arg1,arg2,...]) text {/funcname
+$funcname([arg1,[arg2,...]])
Example 1 (using the "pad" inlinefunc):
- "This is {pad(50,c,-) a center-padded text{/pad of width 50."
+ say This is $pad("a center-padded text", 50,c,-) of width 50.
->
- "This is -------------- a center-padded text--------------- of width 50."
+ John says, "This is -------------- a center-padded text--------------- of width 50."
-Example 2 (using "pad" and "time" inlinefuncs):
- "The time is {pad(30){time(){/time{/padright now."
+Example 2 (using nested "pad" and "time" inlinefuncs):
+ say The time is $pad($time(), 30)right now.
->
- "The time is Oct 25, 11:09 right now."
+ John says, "The time is Oct 25, 11:09 right now."
To add more inline functions, add them to this module, using
the following call signature:
diff --git a/evennia/server/evennia_launcher.py b/evennia/server/evennia_launcher.py
index 2a5ee8b0a5..6ad1818284 100644
--- a/evennia/server/evennia_launcher.py
+++ b/evennia/server/evennia_launcher.py
@@ -805,6 +805,11 @@ def error_check_python_modules():
imp(settings.BASE_ROOM_TYPECLASS)
imp(settings.BASE_EXIT_TYPECLASS)
imp(settings.BASE_SCRIPT_TYPECLASS)
+ # changed game dir settings file names
+ if os.path.isfile(os.path.join("server", "conf", "inlinefunc.py")):
+ raise DeprecationWarning("Name change: mygame/server/conf/inlinefunc.py should "
+ "be renamed to mygame/server/conf/inlinefuncs.py (note the S at the end)")
+
def init_game_directory(path, check_db=True):
diff --git a/evennia/server/sessionhandler.py b/evennia/server/sessionhandler.py
index 2e2291f8e3..28dce77194 100644
--- a/evennia/server/sessionhandler.py
+++ b/evennia/server/sessionhandler.py
@@ -23,8 +23,7 @@ from evennia.utils.utils import (variable_from_module, is_iter,
to_str, to_unicode,
make_iter,
callables_from_module)
-from evennia.utils.inlinefunc import parse_inlinefunc
-from evennia.utils.nested_inlinefuncs import parse_inlinefunc as parse_nested_inlinefunc
+from evennia.utils.inlinefuncs import parse_inlinefunc
try:
import cPickle as pickle
@@ -174,8 +173,7 @@ class SessionHandler(dict):
session.protocol_flags["ENCODING"] = "utf-8"
data = to_str(to_unicode(data), encoding=session.protocol_flags["ENCODING"])
if _INLINEFUNC_ENABLED and not raw:
- data = parse_inlinefunc(data, strip=strip_inlinefunc, session=session) # deprecated!
- data = parse_nested_inlinefunc(data, strip=strip_inlinefunc, session=session)
+ data = parse_inlinefunc(data, strip=strip_inlinefunc, session=session)
return data
elif hasattr(data, "id") and hasattr(data, "db_date_created") \
and hasattr(data, '__dbclass__'):
diff --git a/evennia/settings_default.py b/evennia/settings_default.py
index 076ebd9913..64414789b9 100644
--- a/evennia/settings_default.py
+++ b/evennia/settings_default.py
@@ -396,17 +396,16 @@ TIME_MONTH_PER_YEAR = 12
######################################################################
# Inlinefunc
######################################################################
-# Evennia supports inline function preprocessing. This allows
-# users to supply {func() ... {/func in text, performing dynamic
-# text formatting and manipulation on the fly. If disabled, such
-# inline functions will not be parsed.
+# Evennia supports inline function preprocessing. This allows users
+# to supply inline calls on the form $func(arg, arg, ...) to do
+# session-aware text formatting and manipulation on the fly. If
+# disabled, such inline functions will not be parsed.
INLINEFUNC_ENABLED = False
# Only functions defined globally (and not starting with '_') in
# these modules will be considered valid inlinefuncs. The list
# is loaded from left-to-right, same-named functions will overload
-INLINEFUNC_MODULES = ["evennia.utils.inlinefunc",
- "evennia.utils.nested_inlinefuncs",
- "server.conf.inlinefunc"]
+INLINEFUNC_MODULES = ["evennia.utils.inlinefuncs",
+ "server.conf.inlinefuncs"]
######################################################################
# Default Player setup and access
diff --git a/evennia/utils/inlinefunc.py b/evennia/utils/inlinefunc.py
deleted file mode 100644
index 547e41ebac..0000000000
--- a/evennia/utils/inlinefunc.py
+++ /dev/null
@@ -1,261 +0,0 @@
-"""
-Inlinefunc
-
-**Note: This module is deprecated. Use evennia.utils.nested_inlinefuncs instead.**
-
-This is a simple inline text language for use to custom-format text in
-Evennia. It is applied BEFORE ANSI/MUX parsing is applied.
-
-To activate Inlinefunc, settings.INLINEFUNC_ENABLED must be set.
-
-The format is straightforward:
-
-
-{funcname([arg1,arg2,...]) text {/funcname
-
-
-Example:
- "This is {pad(50,c,-) a center-padded text{/pad of width 50."
- ->
- "This is -------------- a center-padded text--------------- of width 50."
-
-This can be inserted in any text, operated on by the parse_inlinefunc
-function. funcname() (no space is allowed between the name and the
-argument tuple) is picked from a selection of valid functions from
-settings.INLINEFUNC_MODULES.
-
-Commands can be nested, and will applied inside-out. For correct
-parsing their end-tags must match the starting tags in reverse order.
-
-Example:
- "The time is {pad(30){time(){/time{/padright now."
- ->
- "The time is Oct 25, 11:09 right now."
-
-An inline function should have the following call signature:
-
- def funcname(text, *args, **kwargs)
-
-where the text is always the part between {funcname(args) and
-{/funcname and the *args are taken from the appropriate part of the
-call. It is important that the inline function properly clean the
-incoming args, checking their type and replacing them with sane
-defaults if needed. If impossible to resolve, the unmodified text
-should be returned. The inlinefunc should never cause a traceback.
-
-"""
-
-import re
-from django.conf import settings
-from evennia.utils import utils, logger
-
-_DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
-
-# inline functions
-
-def pad(text, *args, **kwargs):
- """
- Pad to width. pad(text, width=78, align='c', fillchar=' ')
-
- """
- width = _DEFAULT_WIDTH
- align = 'c'
- fillchar = ' '
- for iarg, arg in enumerate(args):
- if iarg == 0:
- width = int(arg) if arg.strip().isdigit() else width
- elif iarg == 1:
- align = arg if arg in ('c', 'l', 'r') else align
- elif iarg == 2:
- fillchar = arg[0]
- else:
- break
- return utils.pad(text, width=width, align=align, fillchar=fillchar)
-
-
-def crop(text, *args, **kwargs):
- """
- Crop to width. crop(text, width=78, suffix='[...]')
-
- """
- width = _DEFAULT_WIDTH
- suffix = "[...]"
- for iarg, arg in enumerate(args):
- if iarg == 0:
- width = int(arg) if arg.strip().isdigit() else width
- elif iarg == 1:
- suffix = arg
- else:
- break
- return utils.crop(text, width=width, suffix=suffix)
-
-
-def wrap(text, *args, **kwargs):
- """
- Wrap/Fill text to width. fill(text, width=78, indent=0)
-
- """
- width = _DEFAULT_WIDTH
- indent = 0
- for iarg, arg in enumerate(args):
- if iarg == 0:
- width = int(arg) if arg.strip().isdigit() else width
- elif iarg == 1:
- indent = int(arg) if arg.isdigit() else indent
- return utils.wrap(text, width=width, indent=indent)
-
-
-def time(text, *args, **kwargs):
- """
- Inserts current time.
-
- """
- import time
- strformat = "%h %d, %H:%M"
- if args and args[0]:
- strformat = str(args[0])
- return time.strftime(strformat)
-
-
-def you(text, *args, **kwargs):
- """
- Inserts your name.
-
- """
- name = "You"
- sess = kwargs.get("session")
- if sess and sess.puppet:
- name = sess.puppet.key
- return name
-
-
-# load functions from module (including this one, if using default settings)
-_INLINE_FUNCS = {}
-for module in utils.make_iter(settings.INLINEFUNC_MODULES):
- _INLINE_FUNCS.update(utils.callables_from_module(module))
-_INLINE_FUNCS.pop("inline_func_parse", None)
-
-
-# dynamically build regexes for found functions
-_RE_FUNCFULL = r"\{%s\((.*?)\)(.*?){/%s"
-_RE_FUNCFULL_SINGLE = r"\{%s\((.*?)\)"
-_RE_FUNCSTART = r"\{((?:%s))"
-_RE_FUNCEND = r"\{/((?:%s))"
-_RE_FUNCSPLIT = r"(\{/*(?:%s)(?:\(.*?\))*)"
-_RE_FUNCCLEAN = r"\{%s\(.*?\)|\{/%s"
-
-_INLINE_FUNCS = dict((key, (func, re.compile(_RE_FUNCFULL % (key, key), re.DOTALL & re.MULTILINE),
- re.compile(_RE_FUNCFULL_SINGLE % key, re.DOTALL & re.MULTILINE)))
- for key, func in _INLINE_FUNCS.items() if callable(func))
-_FUNCSPLIT_REGEX = re.compile(_RE_FUNCSPLIT % r"|".join([key for key in _INLINE_FUNCS]), re.DOTALL & re.MULTILINE)
-_FUNCSTART_REGEX = re.compile(_RE_FUNCSTART % r"|".join([key for key in _INLINE_FUNCS]), re.DOTALL & re.MULTILINE)
-_FUNCEND_REGEX = re.compile(_RE_FUNCEND % r"|".join([key for key in _INLINE_FUNCS]), re.DOTALL & re.MULTILINE)
-_FUNCCLEAN_REGEX = re.compile("|".join([_RE_FUNCCLEAN % (key, key) for key in _INLINE_FUNCS]), re.DOTALL & re.MULTILINE)
-
-
-# inline parser functions
-
-def _execute_inline_function(funcname, text, session):
- """
- Get the enclosed text between {funcname(...) and {/funcname
- and execute the inline function to replace the whole block
- with the result.
-
- Args:
- funcname (str): Inlinefunction identifier.
- text (str): Text to process.
- session (Session): Session object.
-
- Notes:
- This lookup is "dumb" - we just grab the first end tag we find. So
- to work correctly this function must be called "inside out" on a
- nested function tree, so each call only works on a "flat" tag.
-
- """
- def subfunc(match):
- """
- replace the entire block with the result of the function call
-
- """
- args = [part.strip() for part in match.group(1).split(",")]
- intext = match.group(2)
- kwargs = {"session":session}
- return _INLINE_FUNCS[funcname][0](intext, *args, **kwargs)
- return _INLINE_FUNCS[funcname][1].sub(subfunc, text)
-
-
-def _execute_inline_single_function(funcname, text, session):
- """
- Get the arguments of a single function call (no matching end tag)
- and execute it with an empty text input.
-
- Args:
- funcname (str): Function identifier.
- text (str): String to process.
- session (Session): Session id.
-
- """
- def subfunc(match):
- "replace the single call with the result of the function call"
- args = [part.strip() for part in match.group(1).split(",")]
- kwargs = {"session":session}
- return _INLINE_FUNCS[funcname][0]("", *args, **kwargs)
- return _INLINE_FUNCS[funcname][2].sub(subfunc, text)
-
-
-def parse_inlinefunc(text, strip=False, session=None):
- """
- Parse inline function-replacement.
-
- Args:
- text (str): Text to parse.
- strip (bool, optional): Remove all supported inlinefuncs from text.
- session (bool): Session calling for the parsing.
-
- Returns:
- text (str): Parsed text with processed results of
- inlinefuncs.
-
- """
-
- if strip:
- # strip all functions
- return _FUNCCLEAN_REGEX.sub("", text)
-
- stack = []
- for part in _FUNCSPLIT_REGEX.split(text):
- endtag = _FUNCEND_REGEX.match(part)
- if endtag:
- # an end tag
- endname = endtag.group(1)
- while stack:
- new_part = stack.pop()
- part = new_part + part # add backwards -> fowards
- starttag = _FUNCSTART_REGEX.match(new_part)
- if starttag:
- startname = starttag.group(1)
- if startname == endname:
- part = _execute_inline_function(startname, part, session)
- break
- stack.append(part)
- # handle single functions without matching end tags; these are treated
- # as being called with an empty string as text argument.
- outstack = []
- for part in _FUNCSPLIT_REGEX.split("".join(stack)):
- starttag = _FUNCSTART_REGEX.match(part)
- if starttag:
- logger.log_dep("The {func()-style inlinefunc is deprecated. Use the $func{} form instead.")
- startname = starttag.group(1)
- part = _execute_inline_single_function(startname, part, session)
- outstack.append(part)
-
- return "".join(outstack)
-
-
-def _test():
- # this should all be handled
- s = "This is a text with a{pad(78,c,-)text {pad(5)of{/pad {pad(30)nice{/pad size{/pad inside {pad(4,l)it{/pad."
- s2 = "This is a text with a----------------text of nice size---------------- inside it ."
- t = parse_inlinefunc(s)
- assert(t == s2)
- return t
diff --git a/evennia/utils/nested_inlinefuncs.py b/evennia/utils/inlinefuncs.py
similarity index 100%
rename from evennia/utils/nested_inlinefuncs.py
rename to evennia/utils/inlinefuncs.py
diff --git a/evennia/utils/tests.py b/evennia/utils/tests.py
index 8e79891efb..9f7afb9d4b 100644
--- a/evennia/utils/tests.py
+++ b/evennia/utils/tests.py
@@ -310,37 +310,37 @@ class TestTextToHTMLparser(TestCase):
'http://example.com/')
-from evennia.utils import nested_inlinefuncs
+from evennia.utils import inlinefuncs
-class TestNestedInlineFuncs(TestCase):
+class TestInlineFuncs(TestCase):
"Test the nested inlinefunc module"
def test_nofunc(self):
- self.assertEqual(nested_inlinefuncs.parse_inlinefunc(
+ self.assertEqual(inlinefuncs.parse_inlinefunc(
"as$382ewrw w we w werw,|44943}"),
"as$382ewrw w we w werw,|44943}")
def test_incomplete(self):
- self.assertEqual(nested_inlinefuncs.parse_inlinefunc(
+ self.assertEqual(inlinefuncs.parse_inlinefunc(
"testing $blah{without an ending."),
"testing $blah{without an ending.")
def test_single_func(self):
- self.assertEqual(nested_inlinefuncs.parse_inlinefunc(
+ self.assertEqual(inlinefuncs.parse_inlinefunc(
"this is a test with $pad(centered, 20) text in it."),
"this is a test with centered text in it.")
def test_nested(self):
- self.assertEqual(nested_inlinefuncs.parse_inlinefunc(
+ self.assertEqual(inlinefuncs.parse_inlinefunc(
"this $crop(is a test with $pad(padded, 20) text in $pad(pad2, 10) a crop, 80)"),
"this is a test with padded text in pad2 a crop")
def test_escaped(self):
- self.assertEqual(nested_inlinefuncs.parse_inlinefunc(
+ self.assertEqual(inlinefuncs.parse_inlinefunc(
"this should be $pad('''escaped,''' and '''instead,''' cropped $crop(with a long,5) text., 80)"),
"this should be escaped, and instead, cropped with text. ")
def test_escaped2(self):
- self.assertEqual(nested_inlinefuncs.parse_inlinefunc(
+ self.assertEqual(inlinefuncs.parse_inlinefunc(
'this should be $pad("""escaped,""" and """instead,""" cropped $crop(with a long,5) text., 80)'),
"this should be escaped, and instead, cropped with text. ")