mirror of
https://github.com/evennia/evennia.git
synced 2026-04-05 07:27:17 +02:00
Clean up docs and more funcparser fixes
This commit is contained in:
parent
12a6c01c2f
commit
dbc4cd7563
21 changed files with 438 additions and 512 deletions
|
|
@ -1,7 +1,5 @@
|
|||
# The Inline Function Parser
|
||||
|
||||
## Introduction
|
||||
|
||||
The [FuncParser](api:evennia.utils.funcparser#evennia.utils.funcparser.FuncParser) extracts and executes
|
||||
'inline functions'
|
||||
embedded in a string on the form `$funcname(args, kwargs)`. Under the hood, this will
|
||||
|
|
@ -11,26 +9,25 @@ the return from the function.
|
|||
```python
|
||||
from evennia.utils.funcparser import FuncParser
|
||||
|
||||
def _square_callable(*args, **kwargs):
|
||||
"""This will be callable as $square(number) in string"""
|
||||
return float(args[0]) ** 2
|
||||
def _power_callable(*args, **kwargs):
|
||||
"""This will be callable as $square(number, power=<num>) in string"""
|
||||
pow = int(kwargs.get('power', 2))
|
||||
return float(args[0]) ** pow
|
||||
|
||||
parser = FuncParser({"square": _square_callable})
|
||||
parser = FuncParser({"pow": _power_callable})
|
||||
|
||||
```
|
||||
Next, just pass a string into the parser, optionally containing `$func(...)` markers:
|
||||
|
||||
```python
|
||||
|
||||
parser.parse("We have that 4 x 4 is $square(4).")
|
||||
"We have that 4 x 4 is 16."
|
||||
|
||||
parser.parse("We have that 4 x 4 x 4 is $pow(4, power=3).")
|
||||
"We have that 4 x 4 x 4 is 64."
|
||||
```
|
||||
|
||||
Normally the return is always converted to a string but you can also get the actual data type from the call:
|
||||
|
||||
```python
|
||||
parser.parse_to_any("$square(4)")
|
||||
parser.parse_to_any("$pow(4)")
|
||||
16
|
||||
```
|
||||
|
||||
|
|
@ -38,8 +35,8 @@ To show a `$func()` verbatim in your code without parsing it, escape it as eithe
|
|||
|
||||
|
||||
```python
|
||||
parser.parse("This is an escaped $$square(4) and so is this \$square(3)")
|
||||
"This is an escaped $square(4) and so is this $square(3)"
|
||||
parser.parse("This is an escaped $$pow(4) and so is this \$pow(3)")
|
||||
"This is an escaped $pow(4) and so is this $pow(3)"
|
||||
```
|
||||
|
||||
## Uses in default Evennia
|
||||
|
|
@ -47,14 +44,14 @@ parser.parse("This is an escaped $$square(4) and so is this \$square(3)")
|
|||
The FuncParser can be applied to any string. Out of the box it's applied in a few situations:
|
||||
|
||||
- _Outgoing messages_. All messages sent from the server is processed through FuncParser and every
|
||||
callable is provided the [Session](Sessions) of the object receiving the message. This potentially
|
||||
callable is provided the [Session](./Sessions) of the object receiving the message. This potentially
|
||||
allows a message to be modified on the fly to look different for different recipients.
|
||||
- _Prototype values_. A [Prototype](Prototypes) dict's values are run through the parser such that every
|
||||
- _Prototype values_. A [Prototype](./Prototypes) dict's values are run through the parser such that every
|
||||
callable gets a reference to the rest of the prototype. In the Prototype ORM, this would allow builders
|
||||
to safely call functions to set non-string values to prototype values, get random values, reference
|
||||
other fields of the prototype, and more.
|
||||
- _Actor-stance in messages to others_. In the
|
||||
[Object.msg_contents](api:evennia.objects.objects#objects.objects.DefaultObject.msg_contents) method,
|
||||
[Object.msg_contents](api:evennia.objects.objects#DefaultObject.msg_contents) method,
|
||||
the outgoing string is parsed for special `$You()` and `$conj()` callables to decide if a given recipient
|
||||
should see "You" or the character's name.
|
||||
|
||||
|
|
@ -115,20 +112,18 @@ The other arguments to the parser:
|
|||
Here's an example of using the default/reserved keywords:
|
||||
|
||||
```python
|
||||
|
||||
def _test(*args, **kwargs):
|
||||
# do stuff
|
||||
return something
|
||||
|
||||
parser = funcparser.FuncParser({"test": _test}, mydefault=2)
|
||||
result = parser.parse("$test(foo, bar=4)", myreserved=[1, 2, 3])
|
||||
|
||||
```
|
||||
Here the callable will be called as
|
||||
|
||||
```python
|
||||
_test('foo', bar='4', mydefault=2, myreserved=[1, 2, 3],
|
||||
funcparser=<FuncParser>, raise_errrors=False)
|
||||
_test('foo', bar='4', mydefault=2, myreserved=[1, 2, 3],
|
||||
funcparser=<FuncParser>, raise_errrors=False)
|
||||
```
|
||||
|
||||
The `mydefault=2` kwarg could be overwritten if we made the call as `$test(mydefault=...)`
|
||||
|
|
@ -154,8 +149,8 @@ an example of an `$toint` function; it converts numbers to integers.
|
|||
"There's a $toint(22.0)% chance of survival."
|
||||
|
||||
What will enter the `$toint` callable (as `args[0]`) is the _string_ `"22.0"`. The function is responsible
|
||||
for converting this to a float so it can operate on it. And also to properly handle invalid inputs (like
|
||||
non-numbers). Common is to just return the input as-is or return the empty string.
|
||||
for converting this to a number so that we can convert it to an integer. We must also properly handle invalid
|
||||
inputs (like non-numbers).
|
||||
|
||||
If you want to mark an error, raise `evennia.utils.funcparser.ParsingError`. This stops the entire parsing
|
||||
of the string and may or may not raise the exception depending on what you set `raise_errors` to when you
|
||||
|
|
@ -167,12 +162,12 @@ Python's `literal_eval` and/or `simple_eval`.
|
|||
|
||||
"There's a $toint($eval(10 * 2.2))% chance of survival."
|
||||
|
||||
Since the `$eval` is the innermost call, it will get a sring as input - the string `"10 * 2.2"`.
|
||||
Since the `$eval` is the innermost call, it will get a string as input - the string `"10 * 2.2"`.
|
||||
It evaluates this and returns the `float` `22.0`. This time the outermost `$toint` will be called with
|
||||
this `float` instead of with a string.
|
||||
|
||||
> Since you don't know in which order users will nest or not nest your callables, it's important to
|
||||
> safely validate your inputs. See the next section for useful tools to do this.
|
||||
> It's important to safely validate your inputs since users may end up nesting your callables in any order.
|
||||
> See the next section for useful tools to help with this.
|
||||
|
||||
In these examples, the result will be embedded in the larger string, so the result of the entire parsing
|
||||
will be a string:
|
||||
|
|
@ -195,16 +190,16 @@ parser.parse_to_any("$toint($eval(10 * 2.2)")
|
|||
### Safe convertion of inputs
|
||||
|
||||
Since you don't know in which order users may use your callables, they should always check the types
|
||||
of its inputs and convert it to type the callable needs. Note also that this limits what inputs you can
|
||||
support since some things (such as complex classes/callables etc) are just not safe/possible to
|
||||
convert from string representation.
|
||||
of its inputs and convert to the type the callable needs. Note also that when converting from strings,
|
||||
there are limits what inputs you can support. This is because FunctionParser strings are often used by
|
||||
non-developer players/builders and some things (such as complex classes/callables etc) are just not
|
||||
safe/possible to convert from string representation.
|
||||
|
||||
In `evennia.utils.utils` is a helper called
|
||||
[safe_convert_to_types](api.evennia.utils.utils#evennia.utils.utils.safe_convert_to_types). This function
|
||||
[safe_convert_to_types](api:evennia.utils.utils#evennia.utils.utils.safe_convert_to_types). This function
|
||||
automates the conversion of simple data types in a safe way:
|
||||
|
||||
```python
|
||||
|
||||
from evennia.utils.utils import safe_convert_to_types
|
||||
|
||||
def _process_callable(*args, **kwargs):
|
||||
|
|
@ -225,7 +220,6 @@ def _process_callable(*args, **kwargs):
|
|||
In other words,
|
||||
|
||||
```python
|
||||
|
||||
args, kwargs = safe_convert_to_type(
|
||||
(tuple_of_arg_converters, dict_of_kwarg_converters), *args, **kwargs)
|
||||
```
|
||||
|
|
@ -245,12 +239,12 @@ following tools (which you may also find useful to experiment with on your own):
|
|||
containers like lists/dicts etc, so this and `literal_eval` are complementary to each other.
|
||||
|
||||
```warning::
|
||||
It may be tempting to run use Python's in-built `eval()` or `exec()` functions as converters since these
|
||||
are able to convert any valid Python source code to Python. NEVER DO THIS unless you really, really
|
||||
know ONLY developers will ever send input to the callable. The parser is intended
|
||||
It may be tempting to run use Python's in-built ``eval()`` or ``exec()`` functions as converters since
|
||||
these are able to convert any valid Python source code to Python. NEVER DO THIS unless you really, really
|
||||
know that ONLY developers will ever modify the string going into the callable. The parser is intended
|
||||
for untrusted users (if you were trusted you'd have access to Python already). Letting untrusted users
|
||||
pass strings to eval/exec is a MAJOR security risk. It allows the caller to effectively run arbitrary
|
||||
Python code on your server. This is the way to maliciously deleted hard drives. Just don't do it and
|
||||
pass strings to ``eval``/``exec`` is a MAJOR security risk. It allows the caller to run arbitrary
|
||||
Python code on your server. This is the path to maliciously deleted hard drives. Just don't do it and
|
||||
sleep better at night.
|
||||
```
|
||||
|
||||
|
|
@ -264,16 +258,16 @@ more to them when you create your `FuncParser` instance to have those callables
|
|||
|
||||
These are the 'base' callables.
|
||||
|
||||
- `$eval(expression)` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_eval) -
|
||||
- `$eval(expression)` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_eval)) -
|
||||
this uses `literal_eval` and `simple_eval` (see previous section) attemt to convert a string expression
|
||||
to a python object. This handles e.g. lists of literals `[1, 2, 3]` and simple expressions like `"1 + 2"`.
|
||||
- `$toint(number)` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_toint)) -
|
||||
always converts an output to an integer, if possible.
|
||||
- `$add/sub/mult/div(obj1, obj2)` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_add))) -
|
||||
- `$add/sub/mult/div(obj1, obj2)` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_add)) -
|
||||
this adds/subtracts/multiplies and divides to elements together. While simple addition could be done with
|
||||
`$eval`, this could for example be used also to add two lists together, which is not possible with `eval`;
|
||||
for example `$add($eval([1,2,3]), $eval([4,5,6])) -> [1, 2, 3, 4, 5, 6]`.
|
||||
- `$round(float, significant)` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_round) -
|
||||
- `$round(float, significant)` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_round)) -
|
||||
rounds an input float into the number of provided significant digits. For example `$round(3.54343, 3) -> 3.543`.
|
||||
- `$random([start, [end]])` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_random)) -
|
||||
this works like the Python `random()` function, but will randomize to an integer value if both start/end are
|
||||
|
|
@ -296,7 +290,7 @@ These are the 'base' callables.
|
|||
- `$ljust` - shortcut to justify-left. Takes all other kwarg of `$just`.
|
||||
- `$rjust` - shortcut to right justify.
|
||||
- `$cjust` - shortcut to center justify.
|
||||
- `$clr(startcolor, text[, endcolor])`([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_clr)) -
|
||||
- `$clr(startcolor, text[, endcolor])` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_clr)) -
|
||||
color text. The color is given with one or two characters without the preceeding `|`. If no endcolor is
|
||||
given, the string will go back to neutral, so `$clr(r, Hello)` is equivalent to `|rHello|n`.
|
||||
|
||||
|
|
@ -310,7 +304,7 @@ parser.parse_to_any(string, caller=<object or account>, access="control", ...)`
|
|||
|
||||
```
|
||||
The `caller` is required, it's the the object to do the access-check for. The `access` kwarg is the
|
||||
[lock type](Locks) to check, default being `"control"`.
|
||||
[lock type](./Locks) to check, default being `"control"`.
|
||||
|
||||
- `$search(query,type=account|script,return_list=False)` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_search)) -
|
||||
this will look up and try to match an object by key or alias. Use the `type` kwarg to
|
||||
|
|
@ -342,9 +336,9 @@ references to other objects accessible via these callables.
|
|||
result of `you_obj.get_display_name(looker=receiver)`. This allows for a single string to echo differently
|
||||
depending on who sees it, and also to reference other people in the same way.
|
||||
- `$You([key])` - same as `$you` but always capitalized.
|
||||
- `$conj(verb)` - conjugates a verb between 2nd person presens to 3rd person presence depending on who
|
||||
sees the string. For example `$You() $conj(smiles).` will show as "You smile." and "Tom smiles." depending
|
||||
on who sees it. This makes use of the tools in [evennia.utils.verb_conjugation](api.evennia.utils.verb_conjugation)
|
||||
- `$conj(verb)` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_conjugate)) -- conjugates a verb between 4nd person presens to 3rd person presence depending on who
|
||||
sees the string. For example `"$You() $conj(smiles)".` will show as "You smile." and "Tom smiles." depending
|
||||
on who sees it. This makes use of the tools in [evennia.utils.verb_conjugation](api:evennia.utils.verb_conjugation)
|
||||
to do this, and only works for English verbs.
|
||||
|
||||
### Example
|
||||
|
|
@ -384,7 +378,5 @@ all the defaults (like `$toint()`).
|
|||
|
||||
The parsed result of the above would be something like this:
|
||||
|
||||
```
|
||||
This is the current uptime:
|
||||
------- 343 seconds -------
|
||||
```
|
||||
This is the current uptime:
|
||||
------- 343 seconds -------
|
||||
21
docs/source/Concepts/Clickable-Links.md
Normal file
21
docs/source/Concepts/Clickable-Links.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
## 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*).
|
||||
|
||||
- `|lc` to start the link, by defining the command to execute.
|
||||
- `|lt` to continue with the text to show to the user (the link text).
|
||||
- `|le` to end the link text and the link definition.
|
||||
|
||||
All elements must appear in exactly this order to make a valid link. For example,
|
||||
|
||||
```
|
||||
"If you go |lcnorth|ltto the north|le you will find a cottage."
|
||||
```
|
||||
|
||||
This will display as "If you go __to the north__ you will find a cottage." where clicking the link
|
||||
will execute the command `north`. If the client does not support clickable links, only the link text
|
||||
will be shown.
|
||||
|
||||
183
docs/source/Concepts/Colors.md
Normal file
183
docs/source/Concepts/Colors.md
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
# Colors
|
||||
|
||||
*Note that the Documentation does not display colour the way it would look on the screen.*
|
||||
|
||||
Color can be a very useful tool for your game. It can be used to increase readability and make your
|
||||
game more appealing visually.
|
||||
|
||||
Remember however that, with the exception of the webclient, you generally don't control the client
|
||||
used to connect to the game. There is, for example, one special tag meaning "yellow". But exactly
|
||||
*which* hue of yellow is actually displayed on the user's screen depends on the settings of their
|
||||
particular mud client. They could even swap the colours around or turn them off altogether if so
|
||||
desired. Some clients don't even support color - text games are also played with special reading
|
||||
equipment by people who are blind or have otherwise diminished eyesight.
|
||||
|
||||
So a good rule of thumb is to use colour to enhance your game but don't *rely* on it to display
|
||||
critical information. If you are coding the game, you can add functionality to let users disable
|
||||
colours as they please, as described [here](../Howto/Manually-Configuring-Color).
|
||||
|
||||
To see which colours your client support, use the default `@color` command. This will list all
|
||||
available colours for ANSI and Xterm256 along with the codes you use for them. You can find a list
|
||||
of all the parsed `ANSI`-colour codes in `evennia/utils/ansi.py`.
|
||||
|
||||
### ANSI colours
|
||||
|
||||
Evennia supports the `ANSI` standard for text. This is by far the most supported MUD-color standard,
|
||||
available in all but the most ancient mud clients. The ANSI colours are **r**ed, **g**reen,
|
||||
**y**ellow, **b**lue, **m**agenta, **c**yan, **w**hite and black. They are abbreviated by their
|
||||
first letter except for black which is abbreviated with the letter **x**. In ANSI there are "bright"
|
||||
and "normal" (darker) versions of each color, adding up to a total of 16 colours to use for
|
||||
foreground text. There are also 8 "background" colours. These have no bright alternative in ANSI
|
||||
(but Evennia uses the [Xterm256](./TextTags#xterm256-colours) extension behind the scenes to offer
|
||||
them anyway).
|
||||
|
||||
To colour your text you put special tags in it. Evennia will parse these and convert them to the
|
||||
correct markup for the client used. If the user's client/console/display supports ANSI colour, they
|
||||
will see the text in the specified colour, otherwise the tags will be stripped (uncolored text).
|
||||
This works also for non-terminal clients, such as the webclient. For the webclient, Evennia will
|
||||
translate the codes to HTML RGB colors.
|
||||
|
||||
Here is an example of the tags in action:
|
||||
|
||||
|rThis text is bright red.|n This is normal text.
|
||||
|RThis is a dark red text.|n This is normal text.
|
||||
|[rThis text has red background.|n This is normal text.
|
||||
|b|[yThis is bright blue text on yellow background.|n This is normal text.
|
||||
|
||||
- `|n` - this tag will turn off all color formatting, including background colors.
|
||||
- `|#`- markup marks the start of foreground color. The case defines if the text is "bright" or
|
||||
"normal". So `|g` is a bright green and `|G` is "normal" (darker) green.
|
||||
- `|[#` is used to add a background colour to the text. The case again specifies if it is "bright"
|
||||
or "normal", so `|[c` starts a bright cyan background and `|[C` a darker cyan background.
|
||||
- `|!#` is used to add foreground color without any enforced brightness/normal information.
|
||||
These are normal-intensity and are thus always given as uppercase, such as
|
||||
`|!R` for red. The difference between e.g. `|!R` and `|R` is that
|
||||
`|!R` will "inherit" the brightness setting from previously set color tags, whereas `|R` will
|
||||
always reset to the normal-intensity red. The `|#` format contains an implicit `|h`/`|H` tag in it:
|
||||
disabling highlighting when switching to a normal color, and enabling it for bright ones. So `|btest
|
||||
|!Rtest2` will result in a bright red `test2` since the brightness setting from `|b` "bleeds over".
|
||||
You could use this to for example quickly switch the intensity of a multitude of color tags. There
|
||||
is no background-color equivalent to `|!` style tags.
|
||||
- `|h` is used to make any following foreground ANSI colors bright (it has no effect on Xterm
|
||||
colors). This is only relevant to use with `|!` type tags and will be valid until the next `|n`,
|
||||
`|H` or normal (upper-case) `|#` tag. This tag will never affect background colors, those have to be
|
||||
set bright/normal explicitly. Technically, `|h|!G` is identical to `|g`.
|
||||
- `|H` negates the effects `|h` and returns all ANSI foreground colors (`|!` and `|` types) to
|
||||
'normal' intensity. It has no effect on background and Xterm colors.
|
||||
|
||||
> Note: The ANSI standard does not actually support bright backgrounds like `|[r` - the standard
|
||||
only supports "normal" intensity backgrounds. To get around this Evennia instead implements these
|
||||
as [Xterm256 colours](./TextTags#xterm256-colours) behind the scenes. If the client does not support
|
||||
Xterm256 the ANSI colors will be used instead and there will be no visible difference between using
|
||||
upper- and lower-case background tags.
|
||||
|
||||
If you want to display an ANSI marker as output text (without having any effect), you need to escape
|
||||
it by preceding its `|` with another `|`:
|
||||
|
||||
```
|
||||
say The ||r ANSI marker changes text color to bright red.
|
||||
```
|
||||
|
||||
This will output the raw `|r` without any color change. This can also be necessary if you are doing
|
||||
ansi art that uses `|` with a letter directly following it.
|
||||
|
||||
Use the command
|
||||
|
||||
@color ansi
|
||||
|
||||
to get a list of all supported ANSI colours and the tags used to produce them.
|
||||
|
||||
A few additional ANSI codes are supported:
|
||||
|
||||
- `|/` A line break. You cannot put the normal Python `\n` line breaks in text entered inside the
|
||||
game (Evennia will filter this for security reasons). This is what you use instead: use the `|/`
|
||||
marker to format text with line breaks from the game command line.
|
||||
- `` This will translate into a `TAB` character. This will not always show (or show differently) to
|
||||
the client since it depends on their local settings. It's often better to use multiple spaces.
|
||||
- `|_` This is a space. You can usually use the normal space character, but if the space is *at the
|
||||
end of the line*, Evennia will likely crop it. This tag will not be cropped but always result in a
|
||||
space.
|
||||
- `|*` This will invert the current text/background colours. Can be useful to mark things (but see
|
||||
below).
|
||||
|
||||
##### Caveats of `|*`
|
||||
|
||||
The `|*` tag (inverse video) is an old ANSI standard and should usually not be used for more than to
|
||||
mark short snippets of text. If combined with other tags it comes with a series of potentially
|
||||
confusing behaviors:
|
||||
|
||||
* The `|*` tag will only work once in a row:, ie: after using it once it won't have an effect again
|
||||
until you declare another tag. This is an example:
|
||||
|
||||
```
|
||||
Normal text, |*reversed text|*, still reversed text.
|
||||
```
|
||||
|
||||
that is, it will not reverse to normal at the second `|*`. You need to reset it manually:
|
||||
|
||||
```
|
||||
Normal text, |*reversed text|n, normal again.
|
||||
```
|
||||
|
||||
* The `|*` tag does not take "bright" colors into account:
|
||||
|
||||
```
|
||||
|RNormal red, |hnow brightened. |*BG is normal red.
|
||||
```
|
||||
|
||||
So `|*` only considers the 'true' foreground color, ignoring any highlighting. Think of the bright
|
||||
state (`|h`) as something like like `<strong>` in HTML: it modifies the _appearance_ of a normal
|
||||
foreground color to match its bright counterpart, without changing its normal color.
|
||||
* Finally, after a `|*`, if the previous background was set to a dark color (via `|[`), `|!#`) will
|
||||
actually change the background color instead of the foreground:
|
||||
|
||||
```
|
||||
|*reversed text |!R now BG is red.
|
||||
```
|
||||
For a detailed explanation of these caveats, see the [Understanding Color Tags](Understanding-Color-
|
||||
Tags) tutorial. But most of the time you might be better off to simply avoid `|*` and mark your text
|
||||
manually instead.
|
||||
|
||||
### Xterm256 Colours
|
||||
|
||||
The _Xterm256_ standard is a colour scheme that supports 256 colours for text and/or background.
|
||||
While this offers many more possibilities than traditional ANSI colours, be wary that too many text
|
||||
colors will be confusing to the eye. Also, not all clients support Xterm256 - these will instead see
|
||||
the closest equivalent ANSI color. You can mix Xterm256 tags with ANSI tags as you please.
|
||||
|
||||
|555 This is pure white text.|n This is normal text.
|
||||
|230 This is olive green text.
|
||||
|[300 This text has a dark red background.
|
||||
|005|[054 This is dark blue text on a bright cyan background.
|
||||
|=a This is a greyscale value, equal to black.
|
||||
|=m This is a greyscale value, midway between white and black.
|
||||
|=z This is a greyscale value, equal to white.
|
||||
|[=m This is a background greyscale value.
|
||||
|
||||
- `|###` - markup consists of three digits, each an integer from 0 to 5. The three digits describe
|
||||
the amount of **r**ed, **g**reen and **b**lue (RGB) components used in the colour. So `|500` means
|
||||
maximum red and none of the other colours - the result is a bright red. `|520` is red with a touch
|
||||
of green - the result is orange. As opposed to ANSI colors, Xterm256 syntax does not worry about
|
||||
bright/normal intensity, a brighter (lighter) color is just achieved by upping all RGB values with
|
||||
the same amount.
|
||||
- `|[###` - this works the same way but produces a coloured background.
|
||||
- `|=#` - markup produces the xterm256 gray scale tones, where `#` is a letter from `a` (black) to
|
||||
`z` (white). This offers many more nuances of gray than the normal `|###` markup (which only has
|
||||
four gray tones between solid black and white (`|000`, `|111`, `|222`, `|333` and `|444`)).
|
||||
- `|[=#` - this works in the same way but produces background gray scale tones.
|
||||
|
||||
If you have a client that supports Xterm256, you can use
|
||||
|
||||
@color xterm256
|
||||
|
||||
to get a table of all the 256 colours and the codes that produce them. If the table looks broken up
|
||||
into a few blocks of colors, it means Xterm256 is not supported and ANSI are used as a replacement.
|
||||
You can use the `@options` command to see if xterm256 is active for you. This depends on if your
|
||||
client told Evennia what it supports - if not, and you know what your client supports, you may have
|
||||
to activate some features manually.
|
||||
|
||||
## More reading
|
||||
|
||||
There is an [Understanding Color Tags](../Howto/Understanding-Color-Tags) tutorial which expands on the
|
||||
use of ANSI color tags and the pitfalls of mixing ANSI and Xterms256 color tags in the same context.
|
||||
|
||||
|
|
@ -1,340 +1,19 @@
|
|||
# TextTags
|
||||
|
||||
|
||||
This documentation details the various text tags supported by Evennia, namely *colours*, *command
|
||||
links* and *inline functions*.
|
||||
|
||||
There is also an [Understanding Color Tags](../Howto/Understanding-Color-Tags) tutorial which expands on the
|
||||
use of ANSI color tags and the pitfalls of mixing ANSI and Xterms256 color tags in the same context.
|
||||
|
||||
## Coloured text
|
||||
|
||||
*Note that the Documentation does not display colour the way it would look on the screen.*
|
||||
|
||||
Color can be a very useful tool for your game. It can be used to increase readability and make your
|
||||
game more appealing visually.
|
||||
|
||||
Remember however that, with the exception of the webclient, you generally don't control the client
|
||||
used to connect to the game. There is, for example, one special tag meaning "yellow". But exactly
|
||||
*which* hue of yellow is actually displayed on the user's screen depends on the settings of their
|
||||
particular mud client. They could even swap the colours around or turn them off altogether if so
|
||||
desired. Some clients don't even support color - text games are also played with special reading
|
||||
equipment by people who are blind or have otherwise diminished eyesight.
|
||||
|
||||
So a good rule of thumb is to use colour to enhance your game but don't *rely* on it to display
|
||||
critical information. If you are coding the game, you can add functionality to let users disable
|
||||
colours as they please, as described [here](../Howto/Manually-Configuring-Color).
|
||||
|
||||
To see which colours your client support, use the default `@color` command. This will list all
|
||||
available colours for ANSI and Xterm256 along with the codes you use for them. You can find a list
|
||||
of all the parsed `ANSI`-colour codes in `evennia/utils/ansi.py`.
|
||||
|
||||
### ANSI colours
|
||||
|
||||
Evennia supports the `ANSI` standard for text. This is by far the most supported MUD-color standard,
|
||||
available in all but the most ancient mud clients. The ANSI colours are **r**ed, **g**reen,
|
||||
**y**ellow, **b**lue, **m**agenta, **c**yan, **w**hite and black. They are abbreviated by their
|
||||
first letter except for black which is abbreviated with the letter **x**. In ANSI there are "bright"
|
||||
and "normal" (darker) versions of each color, adding up to a total of 16 colours to use for
|
||||
foreground text. There are also 8 "background" colours. These have no bright alternative in ANSI
|
||||
(but Evennia uses the [Xterm256](./TextTags#xterm256-colours) extension behind the scenes to offer
|
||||
them anyway).
|
||||
|
||||
To colour your text you put special tags in it. Evennia will parse these and convert them to the
|
||||
correct markup for the client used. If the user's client/console/display supports ANSI colour, they
|
||||
will see the text in the specified colour, otherwise the tags will be stripped (uncolored text).
|
||||
This works also for non-terminal clients, such as the webclient. For the webclient, Evennia will
|
||||
translate the codes to HTML RGB colors.
|
||||
|
||||
Here is an example of the tags in action:
|
||||
|
||||
|rThis text is bright red.|n This is normal text.
|
||||
|RThis is a dark red text.|n This is normal text.
|
||||
|[rThis text has red background.|n This is normal text.
|
||||
|b|[yThis is bright blue text on yellow background.|n This is normal text.
|
||||
|
||||
- `|n` - this tag will turn off all color formatting, including background colors.
|
||||
- `|#`- markup marks the start of foreground color. The case defines if the text is "bright" or
|
||||
"normal". So `|g` is a bright green and `|G` is "normal" (darker) green.
|
||||
- `|[#` is used to add a background colour to the text. The case again specifies if it is "bright"
|
||||
or "normal", so `|[c` starts a bright cyan background and `|[C` a darker cyan background.
|
||||
- `|!#` is used to add foreground color without any enforced brightness/normal information.
|
||||
These are normal-intensity and are thus always given as uppercase, such as
|
||||
`|!R` for red. The difference between e.g. `|!R` and `|R` is that
|
||||
`|!R` will "inherit" the brightness setting from previously set color tags, whereas `|R` will
|
||||
always reset to the normal-intensity red. The `|#` format contains an implicit `|h`/`|H` tag in it:
|
||||
disabling highlighting when switching to a normal color, and enabling it for bright ones. So `|btest
|
||||
|!Rtest2` will result in a bright red `test2` since the brightness setting from `|b` "bleeds over".
|
||||
You could use this to for example quickly switch the intensity of a multitude of color tags. There
|
||||
is no background-color equivalent to `|!` style tags.
|
||||
- `|h` is used to make any following foreground ANSI colors bright (it has no effect on Xterm
|
||||
colors). This is only relevant to use with `|!` type tags and will be valid until the next `|n`,
|
||||
`|H` or normal (upper-case) `|#` tag. This tag will never affect background colors, those have to be
|
||||
set bright/normal explicitly. Technically, `|h|!G` is identical to `|g`.
|
||||
- `|H` negates the effects `|h` and returns all ANSI foreground colors (`|!` and `|` types) to
|
||||
'normal' intensity. It has no effect on background and Xterm colors.
|
||||
|
||||
> Note: The ANSI standard does not actually support bright backgrounds like `|[r` - the standard
|
||||
only supports "normal" intensity backgrounds. To get around this Evennia instead implements these
|
||||
as [Xterm256 colours](./TextTags#xterm256-colours) behind the scenes. If the client does not support
|
||||
Xterm256 the ANSI colors will be used instead and there will be no visible difference between using
|
||||
upper- and lower-case background tags.
|
||||
|
||||
If you want to display an ANSI marker as output text (without having any effect), you need to escape
|
||||
it by preceding its `|` with another `|`:
|
||||
|
||||
```
|
||||
say The ||r ANSI marker changes text color to bright red.
|
||||
```
|
||||
|
||||
This will output the raw `|r` without any color change. This can also be necessary if you are doing
|
||||
ansi art that uses `|` with a letter directly following it.
|
||||
|
||||
Use the command
|
||||
|
||||
@color ansi
|
||||
|
||||
to get a list of all supported ANSI colours and the tags used to produce them.
|
||||
|
||||
A few additional ANSI codes are supported:
|
||||
|
||||
- `|/` A line break. You cannot put the normal Python `\n` line breaks in text entered inside the
|
||||
game (Evennia will filter this for security reasons). This is what you use instead: use the `|/`
|
||||
marker to format text with line breaks from the game command line.
|
||||
- `` This will translate into a `TAB` character. This will not always show (or show differently) to
|
||||
the client since it depends on their local settings. It's often better to use multiple spaces.
|
||||
- `|_` This is a space. You can usually use the normal space character, but if the space is *at the
|
||||
end of the line*, Evennia will likely crop it. This tag will not be cropped but always result in a
|
||||
space.
|
||||
- `|*` This will invert the current text/background colours. Can be useful to mark things (but see
|
||||
below).
|
||||
|
||||
##### Caveats of `|*`
|
||||
|
||||
The `|*` tag (inverse video) is an old ANSI standard and should usually not be used for more than to
|
||||
mark short snippets of text. If combined with other tags it comes with a series of potentially
|
||||
confusing behaviors:
|
||||
|
||||
* The `|*` tag will only work once in a row:, ie: after using it once it won't have an effect again
|
||||
until you declare another tag. This is an example:
|
||||
|
||||
```
|
||||
Normal text, |*reversed text|*, still reversed text.
|
||||
```
|
||||
|
||||
that is, it will not reverse to normal at the second `|*`. You need to reset it manually:
|
||||
|
||||
```
|
||||
Normal text, |*reversed text|n, normal again.
|
||||
```
|
||||
|
||||
* The `|*` tag does not take "bright" colors into account:
|
||||
|
||||
```
|
||||
|RNormal red, |hnow brightened. |*BG is normal red.
|
||||
```
|
||||
|
||||
So `|*` only considers the 'true' foreground color, ignoring any highlighting. Think of the bright
|
||||
state (`|h`) as something like like `<strong>` in HTML: it modifies the _appearance_ of a normal
|
||||
foreground color to match its bright counterpart, without changing its normal color.
|
||||
* Finally, after a `|*`, if the previous background was set to a dark color (via `|[`), `|!#`) will
|
||||
actually change the background color instead of the foreground:
|
||||
|
||||
```
|
||||
|*reversed text |!R now BG is red.
|
||||
```
|
||||
For a detailed explanation of these caveats, see the [Understanding Color Tags](Understanding-Color-
|
||||
Tags) tutorial. But most of the time you might be better off to simply avoid `|*` and mark your text
|
||||
manually instead.
|
||||
|
||||
### Xterm256 Colours
|
||||
|
||||
The _Xterm256_ standard is a colour scheme that supports 256 colours for text and/or background.
|
||||
While this offers many more possibilities than traditional ANSI colours, be wary that too many text
|
||||
colors will be confusing to the eye. Also, not all clients support Xterm256 - these will instead see
|
||||
the closest equivalent ANSI color. You can mix Xterm256 tags with ANSI tags as you please.
|
||||
|
||||
|555 This is pure white text.|n This is normal text.
|
||||
|230 This is olive green text.
|
||||
|[300 This text has a dark red background.
|
||||
|005|[054 This is dark blue text on a bright cyan background.
|
||||
|=a This is a greyscale value, equal to black.
|
||||
|=m This is a greyscale value, midway between white and black.
|
||||
|=z This is a greyscale value, equal to white.
|
||||
|[=m This is a background greyscale value.
|
||||
|
||||
- `|###` - markup consists of three digits, each an integer from 0 to 5. The three digits describe
|
||||
the amount of **r**ed, **g**reen and **b**lue (RGB) components used in the colour. So `|500` means
|
||||
maximum red and none of the other colours - the result is a bright red. `|520` is red with a touch
|
||||
of green - the result is orange. As opposed to ANSI colors, Xterm256 syntax does not worry about
|
||||
bright/normal intensity, a brighter (lighter) color is just achieved by upping all RGB values with
|
||||
the same amount.
|
||||
- `|[###` - this works the same way but produces a coloured background.
|
||||
- `|=#` - markup produces the xterm256 gray scale tones, where `#` is a letter from `a` (black) to
|
||||
`z` (white). This offers many more nuances of gray than the normal `|###` markup (which only has
|
||||
four gray tones between solid black and white (`|000`, `|111`, `|222`, `|333` and `|444`)).
|
||||
- `|[=#` - this works in the same way but produces background gray scale tones.
|
||||
|
||||
If you have a client that supports Xterm256, you can use
|
||||
|
||||
@color xterm256
|
||||
|
||||
to get a table of all the 256 colours and the codes that produce them. If the table looks broken up
|
||||
into a few blocks of colors, it means Xterm256 is not supported and ANSI are used as a replacement.
|
||||
You can use the `@options` command to see if xterm256 is active for you. This depends on if your
|
||||
client told Evennia what it supports - if not, and you know what your client supports, you may have
|
||||
to activate some features manually.
|
||||
|
||||
## 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*).
|
||||
|
||||
- `|lc` to start the link, by defining the command to execute.
|
||||
- `|lt` to continue with the text to show to the user (the link text).
|
||||
- `|le` to end the link text and the link definition.
|
||||
|
||||
All elements must appear in exactly this order to make a valid link. For example,
|
||||
|
||||
```
|
||||
"If you go |lcnorth|ltto the north|le you will find a cottage."
|
||||
```
|
||||
|
||||
This will display as "If you go __to the north__ you will find a cottage." where clicking the link
|
||||
will execute the command `north`. If the client does not support clickable links, only the link text
|
||||
will be shown.
|
||||
|
||||
## Inline functions
|
||||
|
||||
> Note: Inlinefuncs are **not** activated by default. To use them you need to add
|
||||
`INLINEFUNC_ENABLED=True` to your settings file.
|
||||
|
||||
Evennia has its own inline text formatting language, known as *inlinefuncs*. It allows the builder
|
||||
to include special function calls in code. They are executed dynamically by each session that
|
||||
receives them.
|
||||
|
||||
To add an inlinefunc, you embed it in a text string like this:
|
||||
|
||||
```
|
||||
"A normal string with $funcname(arg, arg, ...) embedded inside it."
|
||||
```
|
||||
|
||||
When this string is sent to a session (with the `msg()` method), these embedded inlinefuncs will be
|
||||
parsed. Their return value (which always is a string) replace their call location in the finalized
|
||||
string. The interesting thing with this is that the function called will have access to which
|
||||
session is seeing the string, meaning the string can end up looking different depending on who is
|
||||
looking. It could of course also vary depending on other factors like game time.
|
||||
|
||||
Any number of comma-separated arguments can be given (or none). No keywords are supported. You can
|
||||
also nest inlinefuncs by letting an argument itself also be another `$funcname(arg, arg, ...)` call
|
||||
(down to any depth of nesting). Function call resolution happens as in all programming languages
|
||||
inside-out, with the nested calls replacing the argument with their return strings before calling he
|
||||
parent.
|
||||
|
||||
```
|
||||
> say "This is $pad(a center-padded text, 30,c,-) of width 30."
|
||||
You say, "This is ---- a center-padded text----- of width 30."
|
||||
```
|
||||
|
||||
A special case happens if wanting to use an inlinefunc argument that itself includes a comma - this
|
||||
would be parsed as an argument separator. To escape commas you can either escape each comma manually
|
||||
with a backslash `\,`, or you can embed the entire string in python triple-quotes `"""` or `'''` -
|
||||
this will escape the entire argument, including commas and any nested inlinefunc calls within.
|
||||
|
||||
Only certain functions are available to use as inlinefuncs and the game developer may add their own
|
||||
functions as needed.
|
||||
|
||||
### New inlinefuncs
|
||||
|
||||
To add new inlinefuncs, edit the file `mygame/server/conf/inlinefuncs.py`.
|
||||
|
||||
*All globally defined functions in this module* are considered inline functions by the system. The
|
||||
only exception is functions whose name starts with an underscore `_`. An inlinefunc must be of the
|
||||
following form:
|
||||
|
||||
```python
|
||||
def funcname(*args, **kwargs):
|
||||
# ...
|
||||
return modified_text
|
||||
```
|
||||
|
||||
where `*args` denotes all the arguments this function will accept as an `$inlinefunc`. The inline
|
||||
function is expected to clean arguments and check that they are valid. If needed arguments are not
|
||||
given, default values should be used. The function should always return a string (even if it's
|
||||
empty). An inlinefunc should never cause a traceback regardless of the input (but it could log
|
||||
errors if desired).
|
||||
|
||||
Note that whereas the function should accept `**kwargs`, keyword inputs are *not* usable in the call
|
||||
to the inlinefunction. The `kwargs` part is instead intended for Evennia to be able to supply extra
|
||||
information. Currently Evennia sends a single keyword to every inline function and that is
|
||||
`session`, which holds the [serversession](../Components/Sessions) this text is targeted at. Through the session
|
||||
object, a lot of dynamic possibilities are opened up for your inline functions.
|
||||
|
||||
The `settings.INLINEFUNC_MODULES` configuration option is a list that decides which modules should
|
||||
be parsed for inline function definitions. This will include `mygame/server/conf/inlinefuncs.py` but
|
||||
more could be added. The list is read from left to right so if you want to overload default
|
||||
functions you just have to put your custom module-paths later in the list and name your functions
|
||||
the same as default ones.
|
||||
|
||||
Here is an example, the `crop` default inlinefunction:
|
||||
|
||||
```python
|
||||
from evennia.utils import utils
|
||||
|
||||
def crop(*args, **kwargs):
|
||||
"""
|
||||
Inlinefunc. Crops ingoing text to given widths.
|
||||
Args:
|
||||
text (str, optional): Text to crop.
|
||||
width (str, optional): Will be converted to an integer. Width of
|
||||
crop in characters.
|
||||
suffix (str, optional): End string to mark the fact that a part
|
||||
of the string was cropped. Defaults to `[...]`.
|
||||
Kwargs:
|
||||
session (Session): Session performing the crop.
|
||||
Example:
|
||||
`$crop(text, 50, [...])`
|
||||
|
||||
"""
|
||||
text, width, suffix = "", 78, "[...]"
|
||||
nargs = len(args)
|
||||
if nargs > 0:
|
||||
text = args[0]
|
||||
if nargs > 1:
|
||||
width = int(args[1]) if args[1].strip().isdigit() else 78
|
||||
if nargs > 2:
|
||||
suffix = args[2]
|
||||
return utils.crop(text, width=width, suffix=suffix)
|
||||
```
|
||||
Another example, making use of the Session:
|
||||
|
||||
```python
|
||||
def charactername(*args, **kwargs):
|
||||
"""
|
||||
Inserts the character name of whomever sees the string
|
||||
(so everyone will see their own name). Uses the account
|
||||
name for OOC communications.
|
||||
|
||||
Example:
|
||||
say "This means YOU, $charactername()!"
|
||||
|
||||
"""
|
||||
session = kwargs["session"]
|
||||
if session.puppet:
|
||||
return kwargs["session"].puppet.key
|
||||
else:
|
||||
return session.account.key
|
||||
```
|
||||
|
||||
Evennia itself offers the following default inline functions (mostly as examples):
|
||||
|
||||
* `crop(text, width, suffix)` - See above.
|
||||
* `pad(text, width, align, fillchar)` - this pads the text to `width` (default 78), alignment ("c",
|
||||
"l" or "r", defaulting to "c") and fill-in character (defaults to space). Example: `$pad(40,l,-)`
|
||||
* `clr(startclr, text, endclr)` - A programmatic way to enter colored text for those who don't want
|
||||
to use the normal `|c` type color markers for some reason. The `color` argument is the same as the
|
||||
color markers except without the actual pre-marker, so `|r` would be just `r`. If `endclr` is not
|
||||
given, it defaults to resetting the color (`n`). Example: `$clr(b, A blue text)`
|
||||
* `space(number)` - Inserts the given number of spaces. If no argument is given, use 4 spaces.
|
||||
# In-text tags parsed by Evennia
|
||||
|
||||
Evennia understands various extra information embedded in text:
|
||||
|
||||
- [Colors](./Colors) - Using `|r`, `|n` etc can be used to mark parts of text with a color. The color will
|
||||
become ANSI/XTerm256 color tags for Telnet connections and CSS information for the webclient.
|
||||
- [Clickable links](./Clickable-Links) - This allows you to provide a text the user can click to execute an
|
||||
in-game command. This is on the form `|lc command |lt text |le`.
|
||||
- [FuncParser callables](../Components/FuncParser) - These are full-fledged function calls on the form `$funcname(args, kwargs)`
|
||||
that lead to calls to Python functions. The parser can be run with different available callables in different
|
||||
circumstances. The parser is run on all outgoing messages if `settings.FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED=True`
|
||||
(disabled by default).
|
||||
|
||||
```toctree::
|
||||
|
||||
Colors.md
|
||||
Clickable-Links.md
|
||||
../Components/FuncParser.md
|
||||
```
|
||||
|
|
@ -77,6 +77,7 @@ The flat API is defined in `__init__.py` [viewable here](github:evennia/__init__
|
|||
- [evennia.EvForm](api:evennia.utils.evform#evennia.utils.evform.EvForm) - text form creator
|
||||
- Evennia.EvMore - text paginator
|
||||
- [evennia.EvEditor](api:evennia.utils.eveditor#evennia.utils.eveditor.EvEditor) - in game text line editor ([docs](Components/EvEditor))
|
||||
- [evennia.utils.funcparser.Funcparser](api:evennia.utils.funcparser) - inline parsing of functions ([docs](Components/FuncParser))
|
||||
|
||||
### Global singleton handlers
|
||||
|
||||
|
|
|
|||
7
docs/source/api/evennia.utils.funcparser.rst
Normal file
7
docs/source/api/evennia.utils.funcparser.rst
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
evennia.utils.funcparser
|
||||
===============================
|
||||
|
||||
.. automodule:: evennia.utils.funcparser
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
evennia.utils.inlinefuncs
|
||||
================================
|
||||
|
||||
.. automodule:: evennia.utils.inlinefuncs
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
|
@ -21,8 +21,8 @@ evennia.utils
|
|||
evennia.utils.evmenu
|
||||
evennia.utils.evmore
|
||||
evennia.utils.evtable
|
||||
evennia.utils.funcparser
|
||||
evennia.utils.gametime
|
||||
evennia.utils.inlinefuncs
|
||||
evennia.utils.logger
|
||||
evennia.utils.optionclasses
|
||||
evennia.utils.optionhandler
|
||||
|
|
@ -38,3 +38,4 @@ evennia.utils
|
|||
:maxdepth: 6
|
||||
|
||||
evennia.utils.idmapper
|
||||
evennia.utils.verb_conjugation
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
evennia.utils.verb\_conjugation.conjugate
|
||||
================================================
|
||||
|
||||
.. automodule:: evennia.utils.verb_conjugation.conjugate
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
15
docs/source/api/evennia.utils.verb_conjugation.rst
Normal file
15
docs/source/api/evennia.utils.verb_conjugation.rst
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
evennia.utils.verb\_conjugation
|
||||
=======================================
|
||||
|
||||
.. automodule:: evennia.utils.verb_conjugation
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 6
|
||||
|
||||
evennia.utils.verb_conjugation.conjugate
|
||||
evennia.utils.verb_conjugation.tests
|
||||
7
docs/source/api/evennia.utils.verb_conjugation.tests.rst
Normal file
7
docs/source/api/evennia.utils.verb_conjugation.tests.rst
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
evennia.utils.verb\_conjugation.tests
|
||||
============================================
|
||||
|
||||
.. automodule:: evennia.utils.verb_conjugation.tests
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
# Toc
|
||||
|
||||
- [API root](api/evennia-api.rst)
|
||||
- [Coding/Coding Introduction](Coding/Coding-Introduction)
|
||||
- [Coding/Coding Overview](Coding/Coding-Overview)
|
||||
- [Coding/Continuous Integration](Coding/Continuous-Integration)
|
||||
|
|
@ -53,6 +53,8 @@
|
|||
- [Concepts/Banning](Concepts/Banning)
|
||||
- [Concepts/Bootstrap & Evennia](Concepts/Bootstrap-&-Evennia)
|
||||
- [Concepts/Building Permissions](Concepts/Building-Permissions)
|
||||
- [Concepts/Clickable Links](Concepts/Clickable-Links)
|
||||
- [Concepts/Colors](Concepts/Colors)
|
||||
- [Concepts/Concepts Overview](Concepts/Concepts-Overview)
|
||||
- [Concepts/Custom Protocols](Concepts/Custom-Protocols)
|
||||
- [Concepts/Guest Logins](Concepts/Guest-Logins)
|
||||
|
|
|
|||
|
|
@ -2384,7 +2384,7 @@ class CmdExamine(ObjManipCommand):
|
|||
"""
|
||||
global _FUNCPARSER
|
||||
if not _FUNCPARSER:
|
||||
_FUNCPARSER = funcparser.FuncParser(settings.INLINEFUNC_MODULES)
|
||||
_FUNCPARSER = funcparser.FuncParser(settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES)
|
||||
|
||||
if attr is None:
|
||||
return "No such attribute was found."
|
||||
|
|
@ -3464,7 +3464,7 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
|||
"Python structures are allowed. \nMake sure to use correct "
|
||||
"Python syntax. Remember especially to put quotes around all "
|
||||
"strings inside lists and dicts.|n For more advanced uses, embed "
|
||||
"inlinefuncs in the strings."
|
||||
"funcparser callables ($funcs) in the strings."
|
||||
)
|
||||
else:
|
||||
string = "Expected {}, got {}.".format(expect, type(prototype))
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
"""
|
||||
Inlinefunc
|
||||
Outgoing callables to apply with the FuncParser on outgoing messages.
|
||||
|
||||
Inline functions allow for direct conversion of text users mark in a
|
||||
special way. Inlinefuncs are deactivated by default. To activate, add
|
||||
The functions in this module will become available as $funcname(args, kwargs)
|
||||
in all outgoing strings if you add
|
||||
|
||||
INLINEFUNC_ENABLED = True
|
||||
FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED = True
|
||||
|
||||
to your settings file. The default inlinefuncs are found in
|
||||
evennia.utils.inlinefunc.
|
||||
to your settings file. The default inlinefuncs are found at the bottom of
|
||||
`evennia.utils.funcparser`.
|
||||
|
||||
In text, usage is straightforward:
|
||||
|
||||
$funcname([arg1,[arg2,...]])
|
||||
$funcname(arg1, arg2, ..., key=val, key2=val2, ...)
|
||||
|
||||
Example 1 (using the "pad" inlinefunc):
|
||||
say This is $pad("a center-padded text", 50,c,-) of width 50.
|
||||
|
|
@ -26,26 +26,14 @@ Example 2 (using nested "pad" and "time" inlinefuncs):
|
|||
To add more inline functions, add them to this module, using
|
||||
the following call signature:
|
||||
|
||||
def funcname(text, *args, **kwargs)
|
||||
|
||||
where `text` is always the part between {funcname(args) and
|
||||
{/funcname and the *args are taken from the appropriate part of the
|
||||
call. If no {/funcname is given, `text` will be the empty string.
|
||||
|
||||
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.
|
||||
|
||||
While the inline function should accept **kwargs, the keyword is
|
||||
never accepted as a valid call - this is only intended to be used
|
||||
internally by Evennia, notably to send the `session` keyword to
|
||||
the function; this is the session of the object viewing the string
|
||||
and can be used to customize it to each session.
|
||||
def funcname(*args, **kwargs)
|
||||
...
|
||||
|
||||
"""
|
||||
|
||||
# def capitalize(text, *args, **kwargs):
|
||||
# "Silly capitalize example. Used as {capitalize() ... {/capitalize"
|
||||
# def capitalize(*args, **kwargs):
|
||||
# "Silly capitalize example. Used as $capitalize
|
||||
# if not args:
|
||||
# return ''
|
||||
# session = kwargs.get("session")
|
||||
# return text.capitalize()
|
||||
# return args[0].capitalize()
|
||||
|
|
|
|||
|
|
@ -45,7 +45,12 @@ def protfunc_callable_protkey(*args, **kwargs):
|
|||
|
||||
prototype = kwargs.get("prototype", {})
|
||||
prot_value = prototype[args[0]]
|
||||
return funcparser.funcparser_callable_eval(prot_value, **kwargs)
|
||||
try:
|
||||
return funcparser.funcparser_callable_eval(prot_value, **kwargs)
|
||||
except funcparser.ParsingError:
|
||||
return prot_value
|
||||
|
||||
|
||||
|
||||
|
||||
# this is picked up by FuncParser
|
||||
|
|
|
|||
|
|
@ -59,6 +59,21 @@ def check_errors(settings):
|
|||
"Update your settings file (see evennia/settings_default.py "
|
||||
"for more info)."
|
||||
)
|
||||
depstring = (
|
||||
"settings.{} was renamed to {}. Update your settings file (the FuncParser "
|
||||
"replaces and generalizes that which inlinefuncs used to do).")
|
||||
if hasattr(settings, "INLINEFUNC_ENABLED"):
|
||||
raise DeprecationWarning(depstring.format(
|
||||
"settings.INLINEFUNC_ENABLED", "FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLE"))
|
||||
if hasattr(settings, "INLINEFUNC_STACK_MAXSIZE"):
|
||||
raise DeprecationWarning(depstring.format(
|
||||
"settings.INLINEFUNC_STACK_MAXSIZE", "FUNCPARSER_MAX_NESTING"))
|
||||
if hasattr(settings, "INLINEFUNC_MODULES"):
|
||||
raise DeprecationWarning(depstring.format(
|
||||
"settings.INLINEFUNC_MODULES", "FUNCPARSER_OUTGOING_MESSAGES_MODULES"))
|
||||
if hasattr(settings, "PROTFUNC_MODULES"):
|
||||
raise DeprecationWarning(depstring.format(
|
||||
"settings.PROTFUNC_MODULES", "FUNCPARSER_PROTOTYPE_VALUE_MODULES"))
|
||||
|
||||
gametime_deprecation = (
|
||||
"The settings TIME_SEC_PER_MIN, TIME_MIN_PER_HOUR,"
|
||||
|
|
|
|||
|
|
@ -28,10 +28,9 @@ from evennia.utils.utils import (
|
|||
from evennia.server.portal import amp
|
||||
from evennia.server.signals import SIGNAL_ACCOUNT_POST_LOGIN, SIGNAL_ACCOUNT_POST_LOGOUT
|
||||
from evennia.server.signals import SIGNAL_ACCOUNT_POST_FIRST_LOGIN, SIGNAL_ACCOUNT_POST_LAST_LOGOUT
|
||||
# from evennia.utils.inlinefuncs import parse_inlinefunc
|
||||
from codecs import decode as codecs_decode
|
||||
|
||||
_INLINEFUNC_ENABLED = settings.INLINEFUNC_ENABLED
|
||||
_FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED = settings.FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED
|
||||
|
||||
# delayed imports
|
||||
_AccountDB = None
|
||||
|
|
@ -154,7 +153,8 @@ class SessionHandler(dict):
|
|||
|
||||
def clean_senddata(self, session, kwargs):
|
||||
"""
|
||||
Clean up data for sending across the AMP wire. Also apply INLINEFUNCS.
|
||||
Clean up data for sending across the AMP wire. Also apply the
|
||||
FuncParser using callables from `settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES`.
|
||||
|
||||
Args:
|
||||
session (Session): The relevant session instance.
|
||||
|
|
@ -170,14 +170,14 @@ class SessionHandler(dict):
|
|||
Returns:
|
||||
kwargs (dict): A cleaned dictionary of cmdname:[[args],{kwargs}] pairs,
|
||||
where the keys, args and kwargs have all been converted to
|
||||
send-safe entities (strings or numbers), and inlinefuncs have been
|
||||
send-safe entities (strings or numbers), and funcparser parsing has been
|
||||
applied.
|
||||
|
||||
"""
|
||||
global _FUNCPARSER
|
||||
if not _FUNCPARSER:
|
||||
from evennia.utils.funcparser import FuncParser
|
||||
_FUNCPARSER = FuncParser(settings.INLINEFUNC_MODULES, raise_errors=True)
|
||||
_FUNCPARSER = FuncParser(settings.FUNCPARSER_OUTGOING_MESSAGES_MODULE, raise_errors=True)
|
||||
|
||||
options = kwargs.pop("options", None) or {}
|
||||
raw = options.get("raw", False)
|
||||
|
|
@ -210,8 +210,8 @@ class SessionHandler(dict):
|
|||
elif isinstance(data, (str, bytes)):
|
||||
data = _utf8(data)
|
||||
|
||||
if _INLINEFUNC_ENABLED and not raw and isinstance(self, ServerSessionHandler):
|
||||
# only parse inlinefuncs on the outgoing path (sessionhandler->)
|
||||
if _FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED and not raw and isinstance(self, ServerSessionHandler):
|
||||
# only apply funcparser on the outgoing path (sessionhandler->)
|
||||
# data = parse_inlinefunc(data, strip=strip_inlinefunc, session=session)
|
||||
data = _FUNCPARSER.parse(data, strip=strip_inlinefunc, session=session)
|
||||
|
||||
|
|
|
|||
|
|
@ -598,23 +598,31 @@ TIME_GAME_EPOCH = None
|
|||
TIME_IGNORE_DOWNTIMES = False
|
||||
|
||||
######################################################################
|
||||
# Inlinefunc, PrototypeFuncs
|
||||
# FuncParser
|
||||
#
|
||||
# Strings parsed with the FuncParser can contain 'callables' on the
|
||||
# form $funcname(args,kwargs), which will lead to actual Python functions
|
||||
# being executed.
|
||||
######################################################################
|
||||
# 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
|
||||
# This defined how deeply nested inlinefuncs can be. Set to <=0 to
|
||||
# disable (not recommended, this is a safeguard against infinite loops).
|
||||
INLINEFUNC_STACK_MAXSIZE = 20
|
||||
# This changes the start-symbol for the funcparser callable. Note that
|
||||
# this will make a lot of documentation invalid and there may also be
|
||||
# other unexpected side effects, so change with caution.
|
||||
FUNCPARSER_START_CHAR = '$'
|
||||
# The symbol to use to escape Func
|
||||
FUNCPARSER_ESCAPE_CHAR = '\\'
|
||||
# This is the global max nesting-level for nesting functions in
|
||||
# the funcparser. This protects against infinite loops.
|
||||
FUNCPARSER_MAX_NESTING = 20
|
||||
# Activate funcparser for all outgoing strings. The current Session
|
||||
# will be passed into the parser (used to be called inlinefuncs)
|
||||
FUNCPARSER_PARSE_OUTGOING_MESSAGES_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.funcparser", "server.conf.inlinefuncs"]
|
||||
# Module holding handlers for ProtFuncs. These allow for embedding
|
||||
# functional code in prototypes and has the same syntax as inlinefuncs.
|
||||
PROTOTYPEFUNC_MODULES = ["evennia.prototypes.protfuncs", "server.conf.prototypefuncs"]
|
||||
FUNCPARSER_OUTGOING_MESSAGES_MODULES = ["evennia.utils.funcparser", "server.conf.inlinefuncs"]
|
||||
# Prototype values are also parsed with FuncParser. These modules
|
||||
# define which $func callables are available to use in prototypes.
|
||||
FUNCPARSER_PROTOTYPE_PARSING_MODULES = ["evennia.prototypes.protfuncs", "server.conf.prototypefuncs"]
|
||||
|
||||
######################################################################
|
||||
# Global Scripts
|
||||
|
|
|
|||
|
|
@ -2,10 +2,13 @@
|
|||
Generic function parser for functions embedded in a string, on the form
|
||||
`$funcname(*args, **kwargs)`, for example:
|
||||
|
||||
"A string $foo() with $bar(a, b, c, $moo(), d=23) etc."
|
||||
```
|
||||
"A string $foo() with $bar(a, b, c, $moo(), d=23) etc."
|
||||
```
|
||||
|
||||
Each arg/kwarg can also be another nested function. These will be executed from
|
||||
the deepest-nested first and used as arguments for the higher-level function.
|
||||
Each arg/kwarg can also be another nested function. These will be executed
|
||||
inside-out and their return will used as arguments for the enclosing function
|
||||
(so the same as for regular Python function execution).
|
||||
|
||||
This is the base for all forms of embedded func-parsing, like inlinefuncs and
|
||||
protfuncs. Each function available to use must be registered as a 'safe'
|
||||
|
|
@ -23,7 +26,6 @@ def funcname(*args, **kwargs):
|
|||
# it must always accept *args and **kwargs.
|
||||
...
|
||||
return something
|
||||
|
||||
```
|
||||
|
||||
Usage:
|
||||
|
|
@ -38,6 +40,7 @@ result = parser.parse("String with $funcname() in it")
|
|||
|
||||
The `FuncParser` also accepts a direct dict mapping of `{'name': callable, ...}`.
|
||||
|
||||
---
|
||||
|
||||
"""
|
||||
import re
|
||||
|
|
@ -53,20 +56,21 @@ from evennia.utils.utils import (
|
|||
from evennia.utils import search
|
||||
from evennia.utils.verb_conjugation.conjugate import verb_actor_stance_components
|
||||
|
||||
_CLIENT_DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
|
||||
_MAX_NESTING = 20
|
||||
# setup
|
||||
|
||||
_ESCAPE_CHAR = "\\"
|
||||
_START_CHAR = "$"
|
||||
_CLIENT_DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
|
||||
_MAX_NESTING = settings.FUNCPARSER_MAX_NESTING
|
||||
_START_CHAR = settings.FUNCPARSER_START_CHAR
|
||||
_ESCAPE_CHAR = settings.FUNCPARSER_ESCAPE_CHAR
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class ParsedFunc:
|
||||
class _ParsedFunc:
|
||||
"""
|
||||
Represents a function parsed from the string
|
||||
|
||||
"""
|
||||
prefix: str = "$"
|
||||
prefix: str = _START_CHAR
|
||||
funcname: str = ""
|
||||
args: list = dataclasses.field(default_factory=list)
|
||||
kwargs: dict = dataclasses.field(default_factory=dict)
|
||||
|
|
@ -98,7 +102,8 @@ class ParsingError(RuntimeError):
|
|||
|
||||
class FuncParser:
|
||||
"""
|
||||
Sets up a parser for strings containing $funcname(*args, **kwargs) substrings.
|
||||
Sets up a parser for strings containing `$funcname(*args, **kwargs)`
|
||||
substrings.
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -113,26 +118,23 @@ class FuncParser:
|
|||
|
||||
Args:
|
||||
callables (str, module, list or dict): Where to find
|
||||
'safe' functions to make available in the parser. These modules
|
||||
can have a dict `FUNCPARSER_CALLABLES = {"funcname": callable, ...}`.
|
||||
If no such dict exists, all callables in provided modules (whose names
|
||||
don't start with an underscore) will be loaded as callables. Each
|
||||
callable will will be available to call as `$funcname(*args, **kwags)`
|
||||
during parsing. If `callables` is a `str`, this should be the path
|
||||
to such a module. A `list` can either be a list of paths or module
|
||||
objects. If a `dict`, this should be a direct mapping
|
||||
`{"funcname": callable, ...}` to use.
|
||||
'safe' functions to make available in the parser. If a `dict`,
|
||||
it should be a direct mapping `{"funcname": callable, ...}`. If
|
||||
one or mode modules or module-paths, the module(s) are first checked
|
||||
for a dict `FUNCPARSER_CALLABLES = {"funcname", callable, ...}`. If
|
||||
no such variable exists, all callables in the module (whose name does
|
||||
not start with an underscore) will be made available to the parser.
|
||||
start_char (str, optional): A character used to identify the beginning
|
||||
of a parseable function. Default is `$`.
|
||||
escape_char (str, optional): Prepend characters with this to have
|
||||
them not count as a function. Default is `\\`.
|
||||
them not count as a function. Default is the backtick, `\\\\`.
|
||||
max_nesting (int, optional): How many levels of nested function calls
|
||||
are allowed, to avoid exploitation. Default is 20.
|
||||
**default_kwargs: These kwargs will be passed into all callables. These
|
||||
kwargs can be overridden both by kwargs passed direcetly to `.parse` _and_
|
||||
kwargs can be overridden both by kwargs passed direcetly to `.parse` *and*
|
||||
by kwargs given directly in the string `$funcname` call. They are
|
||||
suitable for global defaults that is intended to be changed by the
|
||||
user. To _guarantee_ a call always gets a particular kwarg, pass it
|
||||
user. To guarantee a call always gets a particular kwarg, pass it
|
||||
into `.parse` as `**reserved_kwargs` instead.
|
||||
|
||||
"""
|
||||
|
|
@ -194,7 +196,7 @@ class FuncParser:
|
|||
Execute a parsed function
|
||||
|
||||
Args:
|
||||
parsedfunc (ParsedFunc): This dataclass holds the parsed details
|
||||
parsedfunc (_ParsedFunc): This dataclass holds the parsed details
|
||||
of the function.
|
||||
raise_errors (bool, optional): Raise errors. Otherwise return the
|
||||
string with the function unparsed.
|
||||
|
|
@ -254,9 +256,9 @@ class FuncParser:
|
|||
def parse(self, string, raise_errors=False, escape=False,
|
||||
strip=False, return_str=True, **reserved_kwargs):
|
||||
"""
|
||||
Use parser to parse a string that may or may not have `$funcname(*args, **kwargs)`
|
||||
- style tokens in it. Only the callables used to initiate the parser
|
||||
will be eligible for parsing, others will remain un-parsed.
|
||||
Use parser to parse a string that may or may not have
|
||||
`$funcname(*args, **kwargs)` - style tokens in it. Only the callables
|
||||
used to initiate the parser will be eligible for parsing.
|
||||
|
||||
Args:
|
||||
string (str): The string to parse.
|
||||
|
|
@ -357,7 +359,7 @@ class FuncParser:
|
|||
callstack.append(curr_func)
|
||||
|
||||
# start a new func
|
||||
curr_func = ParsedFunc(prefix=char, fullstr=char)
|
||||
curr_func = _ParsedFunc(prefix=char, fullstr=char)
|
||||
continue
|
||||
|
||||
if not curr_func:
|
||||
|
|
@ -592,16 +594,16 @@ def funcparser_callable_eval(*args, **kwargs):
|
|||
incoming string into a python object. If it fails, the return will be same
|
||||
as the input.
|
||||
|
||||
Args
|
||||
Args:
|
||||
string (str): The string to parse. Only simple literals or operators are allowed.
|
||||
|
||||
Returns:
|
||||
any: The string parsed into its Python form, or the same as input.
|
||||
|
||||
Example:
|
||||
`$py(1)`
|
||||
`$py([1,2,3,4])`
|
||||
`$py(3 + 4)`
|
||||
Examples:
|
||||
- `$py(1) -> 1`
|
||||
- `$py([1,2,3,4] -> [1, 2, 3]`
|
||||
- `$py(3 + 4) -> 7`
|
||||
|
||||
"""
|
||||
args, kwargs = safe_convert_to_types(("py", {}) , *args, **kwargs)
|
||||
|
|
@ -652,22 +654,22 @@ def _apply_operation_two_elements(*args, operator="+", **kwargs):
|
|||
|
||||
|
||||
def funcparser_callable_add(*args, **kwargs):
|
||||
"""Usage: $add(val1, val2) -> val1 + val2"""
|
||||
"""Usage: `$add(val1, val2) -> val1 + val2`"""
|
||||
return _apply_operation_two_elements(*args, operator='+', **kwargs)
|
||||
|
||||
|
||||
def funcparser_callable_sub(*args, **kwargs):
|
||||
"""Usage: $sub(val1, val2) -> val1 - val2"""
|
||||
"""Usage: ``$sub(val1, val2) -> val1 - val2`"""
|
||||
return _apply_operation_two_elements(*args, operator='-', **kwargs)
|
||||
|
||||
|
||||
def funcparser_callable_mult(*args, **kwargs):
|
||||
"""Usage: $mult(val1, val2) -> val1 * val2"""
|
||||
"""Usage: `$mult(val1, val2) -> val1 * val2`"""
|
||||
return _apply_operation_two_elements(*args, operator='*', **kwargs)
|
||||
|
||||
|
||||
def funcparser_callable_div(*args, **kwargs):
|
||||
"""Usage: $mult(val1, val2) -> val1 / val2"""
|
||||
"""Usage: `$mult(val1, val2) -> val1 / val2`"""
|
||||
return _apply_operation_two_elements(*args, operator='/', **kwargs)
|
||||
|
||||
|
||||
|
|
@ -686,8 +688,8 @@ def funcparser_callable_round(*args, **kwargs):
|
|||
any: The rounded value or inp if inp was not a number.
|
||||
|
||||
Examples:
|
||||
- `$round(3.5434343, 3)` - gives 3.543
|
||||
- `$round($random(), 2)` - rounds random result, e.g 0.22
|
||||
- `$round(3.5434343, 3) -> 3.543`
|
||||
- `$round($random(), 2)` - rounds random result, e.g `0.22`
|
||||
|
||||
"""
|
||||
if not args:
|
||||
|
|
@ -738,7 +740,7 @@ def funcparser_callable_random(*args, **kwargs):
|
|||
|
||||
try:
|
||||
if isinstance(minval, float) or isinstance(maxval, float):
|
||||
return minval + maxval * random.random()
|
||||
return minval + ((maxval - minval) * random.random())
|
||||
else:
|
||||
return random.randint(minval, maxval)
|
||||
except Exception:
|
||||
|
|
@ -794,8 +796,8 @@ def funcparser_callable_pad(*args, **kwargs):
|
|||
fillchar (str, optional): Character used for padding. Defaults to a space.
|
||||
|
||||
Example:
|
||||
- `$pad(text, 12, l, ' ')`
|
||||
- `$pad(text, width=12, align=c, fillchar=-)`
|
||||
- `$pad(text, 12, r, ' ') -> " text"`
|
||||
- `$pad(text, width=12, align=c, fillchar=-) -> "----text----"`
|
||||
|
||||
"""
|
||||
if not args:
|
||||
|
|
@ -829,8 +831,8 @@ def funcparser_callable_crop(*args, **kwargs):
|
|||
of the string was cropped. Defaults to `[...]`.
|
||||
|
||||
Example:
|
||||
`$crop(text, 78, [...])`
|
||||
`$crop(text, width=78, suffix='[...]')`
|
||||
- `$crop(A long text, 10, [...]) -> "A lon[...]"`
|
||||
- `$crop(text, width=11, suffix='[...]) -> "A long[...]"`
|
||||
|
||||
"""
|
||||
if not args:
|
||||
|
|
@ -875,8 +877,8 @@ def funcparser_callable_justify(*args, **kwargs):
|
|||
str: The justified text.
|
||||
|
||||
Examples:
|
||||
- $just(text, width=40)
|
||||
- $just(text, align=r, indent=2)
|
||||
- `$just(text, width=40)`
|
||||
- `$just(text, align=r, indent=2)`
|
||||
|
||||
"""
|
||||
if not args:
|
||||
|
|
@ -925,9 +927,9 @@ def funcparser_callable_clr(*args, **kwargs):
|
|||
color (str, optional): If given,
|
||||
|
||||
Example:
|
||||
- `$clr(r, text, n)`
|
||||
- `$clr(r, text)`
|
||||
- `$clr(text, start=r, end=n)`
|
||||
- `$clr(r, text, n) -> "|rtext|n"`
|
||||
- `$clr(r, text) -> "|rtext|n`
|
||||
- `$clr(text, start=r, end=n) -> "|rtext|n"`
|
||||
|
||||
"""
|
||||
if not args:
|
||||
|
|
@ -961,7 +963,7 @@ def funcparser_callable_search(*args, caller=None, access="control", **kwargs):
|
|||
Args:
|
||||
query (str): The key or dbref to search for.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
return_list (bool): If set, return a list of objects with
|
||||
0, 1 or more matches to `query`. Defaults to False.
|
||||
type (str): One of 'obj', 'account', 'script'
|
||||
|
|
@ -1037,7 +1039,7 @@ def funcparser_callable_you(*args, caller=None, receiver=None, mapping=None, cap
|
|||
Replaces with you for the caller of the string, with the display_name
|
||||
of the caller for others.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
caller (Object): The 'you' in the string. This is used unless another
|
||||
you-key is passed to the callable in combination with `mapping`.
|
||||
receiver (Object): The recipient of the string.
|
||||
|
|
@ -1093,10 +1095,9 @@ def funcparser_callable_You(*args, you=None, receiver=None, mapping=None, capita
|
|||
|
||||
def funcparser_callable_conjugate(*args, caller=None, receiver=None, **kwargs):
|
||||
"""
|
||||
$conj(verb)
|
||||
|
||||
Conjugate a verb according to if it should be 2nd or third person.
|
||||
Kwargs:
|
||||
|
||||
Keyword Args:
|
||||
caller (Object): The object who represents 'you' in the string.
|
||||
receiver (Object): The recipient of the string.
|
||||
|
||||
|
|
@ -1107,13 +1108,12 @@ def funcparser_callable_conjugate(*args, caller=None, receiver=None, **kwargs):
|
|||
ParsingError: If `you` and `recipient` were not both supplied.
|
||||
|
||||
Notes:
|
||||
Note that it will not capitalized.
|
||||
This assumes that the active party (You) is the one performing the verb.
|
||||
Note that the verb will not be capitalized. It also
|
||||
assumes that the active party (You) is the one performing the verb.
|
||||
This automatic conjugation will fail if the active part is another person
|
||||
than 'you'.
|
||||
The you/receiver should be passed to the parser directly.
|
||||
than 'you'. The caller/receiver must be passed to the parser directly.
|
||||
|
||||
Exampels:
|
||||
Examples:
|
||||
This is often used in combination with the $you/You( callables.
|
||||
|
||||
- `With a grin, $you() $conj(jump)`
|
||||
|
|
|
|||
|
|
@ -348,18 +348,19 @@ class TestDefaultCallables(TestCase):
|
|||
|
||||
def test_random(self):
|
||||
string = "$random(1,10)"
|
||||
ret = self.parser.parse_to_any(string, raise_errors=True)
|
||||
self.assertTrue(1 <= ret <= 10)
|
||||
for i in range(100):
|
||||
ret = self.parser.parse_to_any(string, raise_errors=True)
|
||||
self.assertTrue(1 <= ret <= 10)
|
||||
|
||||
string = "$random()"
|
||||
ret = self.parser.parse_to_any(string, raise_errors=True)
|
||||
self.assertTrue(0 <= ret <= 1)
|
||||
for i in range(100):
|
||||
ret = self.parser.parse_to_any(string, raise_errors=True)
|
||||
self.assertTrue(0 <= ret <= 1)
|
||||
|
||||
string = "$random(1.0, 3.0)"
|
||||
for i in range(1000):
|
||||
for i in range(100):
|
||||
ret = self.parser.parse_to_any(string, raise_errors=True)
|
||||
self.assertTrue(isinstance(ret, float))
|
||||
print("ret:", ret)
|
||||
self.assertTrue(1.0 <= ret <= 3.0)
|
||||
|
||||
def test_randint(self):
|
||||
|
|
|
|||
|
|
@ -1080,7 +1080,8 @@ def repeat(interval, callback, persistent=True, idstring="", stop=False,
|
|||
store_key (tuple, optional): This is only used in combination with `stop` and
|
||||
should be the return given from the original `repeat` call. If this
|
||||
is given, all other args except `stop` are ignored.
|
||||
*args, **kwargs: Used as arguments to `callback`.
|
||||
*args: Used as arguments to `callback`.
|
||||
**kwargs: Keyword-arguments to pass to `callback`.
|
||||
|
||||
Returns:
|
||||
tuple or None: The tuple is the `store_key` - the identifier for the
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue