Start tutorialmenu
This commit is contained in:
parent
300429a03f
commit
b89d188c32
4 changed files with 178 additions and 386 deletions
|
|
@ -1,383 +0,0 @@
|
||||||
"""
|
|
||||||
Game tutor
|
|
||||||
|
|
||||||
Evennia contrib - Griatch 2020
|
|
||||||
|
|
||||||
This contrib is a system for easily adding a tutor/tutorial for your game
|
|
||||||
(something that should be considered a necessity for any game ...).
|
|
||||||
|
|
||||||
It consists of a single room that will be created for each player/character
|
|
||||||
wanting to go through the tutorial. The text is presented as a menu of
|
|
||||||
self-sustained 'lessons' that the user can either jump freely between or step
|
|
||||||
through wizard-style. In each lesson, the tutor will track progress (for
|
|
||||||
example the user may be asked to try out a certain command, and the tutor will
|
|
||||||
not move on until that command has been tried).
|
|
||||||
::
|
|
||||||
# node Start
|
|
||||||
|
|
||||||
Neque ea alias perferendis molestiae eligendi. Debitis exercitationem
|
|
||||||
exercitationem quas blanditiis quisquam officia ut. Fugit aut fugit enim quia
|
|
||||||
non. Earum et excepturi animi ex esse accusantium et. Id adipisci eos enim
|
|
||||||
ratione.
|
|
||||||
|
|
||||||
## options
|
|
||||||
|
|
||||||
1: first option -> node1
|
|
||||||
2: second option -> node2
|
|
||||||
3: node3 -> gotonode3()
|
|
||||||
next;n: node2
|
|
||||||
top: start
|
|
||||||
>input: return to go back -> start
|
|
||||||
>input foo*: foo()
|
|
||||||
>input bar*: bar()
|
|
||||||
|
|
||||||
# node node1
|
|
||||||
|
|
||||||
Neque ea alias perferendis molestiae eligendi. Debitis exercitationem
|
|
||||||
exercitationem quas blanditiis quisquam officia ut. Fugit aut fugit enim quia
|
|
||||||
non. Earum et excepturi animi ex esse accusantium et. Id adipisci eos enim
|
|
||||||
ratione.
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import re
|
|
||||||
from ast import literal_eval
|
|
||||||
|
|
||||||
from evennia import EvMenu
|
|
||||||
from fnmatch import fnmatch
|
|
||||||
|
|
||||||
# i18n
|
|
||||||
from django.utils.translation import gettext as _
|
|
||||||
|
|
||||||
_RE_NODE = re.compile(r"#\s*?NODE\s+?(?P<nodename>\S+?)$", re.I + re.M)
|
|
||||||
_RE_OPTIONS_SEP = re.compile(r"##\s*?OPTIONS*?\s*?$", re.I + re.M)
|
|
||||||
_RE_CALLABLE = re.compile(r"\S+?\(\)", re.I + re.M)
|
|
||||||
_RE_CALLABLE = re.compile(
|
|
||||||
r"(?P<funcname>\S+?)(?:\((?P<kwargs>[\S\s]+?=[\S\s]+?)\)|\(\))", re.I + re.M
|
|
||||||
)
|
|
||||||
|
|
||||||
_HELP_NO_OPTION_MATCH = _("Choose an option or try 'help'.")
|
|
||||||
|
|
||||||
_OPTION_INPUT_MARKER = ">"
|
|
||||||
_OPTION_ALIAS_MARKER = ";"
|
|
||||||
_OPTION_SEP_MARKER = ":"
|
|
||||||
_OPTION_CALL_MARKER = "->"
|
|
||||||
_OPTION_COMMENT_START = "#"
|
|
||||||
|
|
||||||
|
|
||||||
# Input/option/goto handler functions that allows for dynamically generated
|
|
||||||
# nodes read from the menu template.
|
|
||||||
|
|
||||||
|
|
||||||
def _generated_goto_func(caller, raw_string, **kwargs):
|
|
||||||
goto = kwargs["goto"]
|
|
||||||
goto_callables = kwargs["goto_callables"]
|
|
||||||
current_nodename = kwargs["current_nodename"]
|
|
||||||
|
|
||||||
if _RE_CALLABLE.match(goto):
|
|
||||||
gotofunc = goto.strip()[:-2]
|
|
||||||
if gotofunc in goto_callables:
|
|
||||||
goto = goto_callables[gotofunc](caller, raw_string, **kwargs)
|
|
||||||
if goto is None:
|
|
||||||
return goto, {"generated_nodename": current_nodename}
|
|
||||||
caller.msg(_HELP_NO_OPTION_MATCH)
|
|
||||||
return goto, {"generated_nodename": goto}
|
|
||||||
|
|
||||||
|
|
||||||
def _generated_input_goto_func(caller, raw_string, **kwargs):
|
|
||||||
gotomap = kwargs["gotomap"]
|
|
||||||
goto_callables = kwargs["goto_callables"]
|
|
||||||
current_nodename = kwargs["current_nodename"]
|
|
||||||
|
|
||||||
# start with glob patterns
|
|
||||||
for pattern, goto in gotomap.items():
|
|
||||||
if fnmatch(raw_string.lower(), pattern):
|
|
||||||
match = _RE_CALLABLE.match(goto)
|
|
||||||
print(f"goto {goto} -> match: {match}")
|
|
||||||
if match:
|
|
||||||
gotofunc = match.group("funcname")
|
|
||||||
gotokwargs = match.group("kwargs") or ""
|
|
||||||
print(f"gotofunc: {gotofunc}, {gotokwargs}")
|
|
||||||
if gotofunc in goto_callables:
|
|
||||||
for kwarg in gotokwargs.split(","):
|
|
||||||
if kwarg and "=" in kwarg:
|
|
||||||
print(f"kwarg {kwarg}")
|
|
||||||
key, value = [part.strip() for part in kwarg.split("=", 1)]
|
|
||||||
try:
|
|
||||||
key = literal_eval(key)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
value = literal_eval(value)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
kwargs[key] = value
|
|
||||||
goto = goto_callables[gotofunc](caller, raw_string, **kwargs)
|
|
||||||
if goto is None:
|
|
||||||
return goto, {"generated_nodename": current_nodename}
|
|
||||||
return goto, {"generated_nodename": goto}
|
|
||||||
# no glob pattern match; try regex
|
|
||||||
for pattern, goto in gotomap.items():
|
|
||||||
if re.match(pattern, raw_string.lower(), flags=re.I + re.M):
|
|
||||||
if _RE_CALLABLE.match(goto):
|
|
||||||
gotofunc = goto.strip()[:-2]
|
|
||||||
if gotofunc in goto_callables:
|
|
||||||
goto = goto_callables[gotofunc](caller, raw_string, **kwargs)
|
|
||||||
if goto is None:
|
|
||||||
return goto, {"generated_nodename": current_nodename}
|
|
||||||
return goto, {"generated_nodename": goto}
|
|
||||||
# no match, rerun current node
|
|
||||||
caller.msg(_HELP_NO_OPTION_MATCH)
|
|
||||||
return None, {"generated_nodename": current_nodename}
|
|
||||||
|
|
||||||
|
|
||||||
def _generated_node(caller, raw_string, **kwargs):
|
|
||||||
text, options = caller.db._generated_menu_contents[kwargs["_current_nodename"]]
|
|
||||||
return text, options
|
|
||||||
|
|
||||||
|
|
||||||
def parse_menu_template(caller, menu_template, goto_callables=None):
|
|
||||||
"""
|
|
||||||
Parse menu-template string
|
|
||||||
|
|
||||||
Args:
|
|
||||||
caller (Object or Account): Entity using the menu.
|
|
||||||
menu_template (str): Menu described using the templating format.
|
|
||||||
goto_callables (dict, optional): Mapping between call-names and callables
|
|
||||||
on the form `callable(caller, raw_string, **kwargs)`. These are what is
|
|
||||||
available to use in the `menu_template` string.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
def _parse_options(nodename, optiontxt, goto_callables):
|
|
||||||
"""
|
|
||||||
Parse option section into option dict.
|
|
||||||
"""
|
|
||||||
options = []
|
|
||||||
optiontxt = optiontxt[0].strip() if optiontxt else ""
|
|
||||||
optionlist = [optline.strip() for optline in optiontxt.split("\n")]
|
|
||||||
inputparsemap = {}
|
|
||||||
|
|
||||||
for inum, optline in enumerate(optionlist):
|
|
||||||
if optline.startswith(_OPTION_COMMENT_START) or _OPTION_SEP_MARKER not in optline:
|
|
||||||
# skip comments or invalid syntax
|
|
||||||
continue
|
|
||||||
key = ""
|
|
||||||
desc = ""
|
|
||||||
pattern = None
|
|
||||||
|
|
||||||
key, goto = [part.strip() for part in optline.split(_OPTION_SEP_MARKER, 1)]
|
|
||||||
|
|
||||||
# desc -> goto
|
|
||||||
if _OPTION_CALL_MARKER in goto:
|
|
||||||
desc, goto = [part.strip() for part in goto.split(_OPTION_CALL_MARKER, 1)]
|
|
||||||
|
|
||||||
# parse key [;aliases|pattern]
|
|
||||||
key = [part.strip() for part in key.split(_OPTION_ALIAS_MARKER)]
|
|
||||||
if not key:
|
|
||||||
# fall back to this being the Nth option
|
|
||||||
key = [f"{inum + 1}"]
|
|
||||||
main_key = key[0]
|
|
||||||
|
|
||||||
if main_key.startswith(_OPTION_INPUT_MARKER):
|
|
||||||
# if we have a pattern, build the arguments for _default later
|
|
||||||
pattern = main_key[len(_OPTION_INPUT_MARKER) :].strip()
|
|
||||||
inputparsemap[pattern] = goto
|
|
||||||
print(f"registering input goto {pattern} -> {goto}")
|
|
||||||
else:
|
|
||||||
# a regular goto string/callable target
|
|
||||||
option = {
|
|
||||||
"key": key,
|
|
||||||
"goto": (
|
|
||||||
_generated_goto_func,
|
|
||||||
{
|
|
||||||
"goto": goto,
|
|
||||||
"current_nodename": nodename,
|
|
||||||
"goto_callables": goto_callables,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
}
|
|
||||||
if desc:
|
|
||||||
option["desc"] = desc
|
|
||||||
options.append(option)
|
|
||||||
|
|
||||||
if inputparsemap:
|
|
||||||
# if this exists we must create a _default entry too
|
|
||||||
options.append(
|
|
||||||
{
|
|
||||||
"key": "_default",
|
|
||||||
"goto": (
|
|
||||||
_generated_input_goto_func,
|
|
||||||
{
|
|
||||||
"gotomap": inputparsemap,
|
|
||||||
"current_nodename": nodename,
|
|
||||||
"goto_callables": goto_callables,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return options
|
|
||||||
|
|
||||||
def _parse(caller, menu_template, goto_callables):
|
|
||||||
"""
|
|
||||||
Parse the menu string format into a node tree.
|
|
||||||
"""
|
|
||||||
nodetree = {}
|
|
||||||
splits = _RE_NODE.split(menu_template)
|
|
||||||
splits = splits[1:] if splits else []
|
|
||||||
|
|
||||||
# from evennia import set_trace;set_trace(term_size=(140,120))
|
|
||||||
content_map = {}
|
|
||||||
for node_ind in range(0, len(splits), 2):
|
|
||||||
nodename, nodetxt = splits[node_ind], splits[node_ind + 1]
|
|
||||||
text, *optiontxt = _RE_OPTIONS_SEP.split(nodetxt, maxsplit=2)
|
|
||||||
options = _parse_options(nodename, optiontxt, goto_callables)
|
|
||||||
content_map[nodename] = (text, options)
|
|
||||||
nodetree[nodename] = _generated_node
|
|
||||||
caller.db._generated_menu_contents = content_map
|
|
||||||
|
|
||||||
return nodetree
|
|
||||||
|
|
||||||
return _parse(caller, menu_template, goto_callables)
|
|
||||||
|
|
||||||
|
|
||||||
def template2menu(
|
|
||||||
caller,
|
|
||||||
menu_template,
|
|
||||||
goto_callables=None,
|
|
||||||
startnode="start",
|
|
||||||
persistent=False,
|
|
||||||
**kwargs,
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
Helper function to generate and start an EvMenu based on a menu template
|
|
||||||
string.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
caller (Object or Account): The entity using the menu.
|
|
||||||
menu_template (str): The menu-template string describing the content
|
|
||||||
and structure of the menu. It can also be the python-path to, or a module
|
|
||||||
containing a `MENU_TEMPLATE` global variable with the template.
|
|
||||||
goto_callables (dict, optional): Mapping of callable-names to
|
|
||||||
module-global objects to reference by name in the menu-template.
|
|
||||||
Must be on the form `callable(caller, raw_string, **kwargs)`.
|
|
||||||
startnode (str, optional): The name of the startnode, if not 'start'.
|
|
||||||
persistent (bool, optional): If the generated menu should be persistent.
|
|
||||||
**kwargs: All kwargs will be passed into EvMenu.
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
goto_callables = goto_callables or {}
|
|
||||||
menu_tree = parse_menu_template(caller, menu_template, goto_callables)
|
|
||||||
EvMenu(
|
|
||||||
caller,
|
|
||||||
menu_tree,
|
|
||||||
persistent=persistent,
|
|
||||||
**kwargs,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def gotonode3(caller, raw_string, **kwargs):
|
|
||||||
print("in gotonode3", caller, raw_string, kwargs)
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def foo(caller, raw_string, **kwargs):
|
|
||||||
print("in foo", caller, raw_string, kwargs)
|
|
||||||
return "node2"
|
|
||||||
|
|
||||||
|
|
||||||
def bar(caller, raw_string, **kwargs):
|
|
||||||
print("in bar", caller, raw_string, kwargs)
|
|
||||||
return "bar"
|
|
||||||
|
|
||||||
|
|
||||||
def customcall(caller, raw_string, **kwargs):
|
|
||||||
return "start"
|
|
||||||
|
|
||||||
def customnode(caller, raw_string, **kwargs):
|
|
||||||
text = "This is a custom node!"
|
|
||||||
options = {
|
|
||||||
"desc": "Go back",
|
|
||||||
"goto": customcall
|
|
||||||
}
|
|
||||||
return text, options
|
|
||||||
|
|
||||||
def test_generator(caller):
|
|
||||||
|
|
||||||
MENU_TEMPLATE = """
|
|
||||||
# node start
|
|
||||||
|
|
||||||
Neque ea alias perferendis molestiae eligendi. Debitis exercitationem
|
|
||||||
exercitationem quas blanditiis quisquam officia ut. Fugit aut fugit enim quia
|
|
||||||
non. Earum et excepturi animi ex esse accusantium et. Id adipisci eos enim
|
|
||||||
ratione.
|
|
||||||
|
|
||||||
## options
|
|
||||||
|
|
||||||
1: first option -> node1
|
|
||||||
2: second option -> node2
|
|
||||||
3: node3 -> gotonode3()
|
|
||||||
next;n: node2
|
|
||||||
top: start
|
|
||||||
> foo*: foo()
|
|
||||||
> bar*: bar(a=4, boo=groo)
|
|
||||||
> [5,6]0+?: foo()
|
|
||||||
> great: node2
|
|
||||||
> fail: bar()
|
|
||||||
|
|
||||||
# node node1
|
|
||||||
|
|
||||||
Neque ea alias perferendis molestiae eligendi. Debitis exercitationem
|
|
||||||
exercitationem quas blanditiis quisquam officia ut. Fugit aut fugit enim quia
|
|
||||||
non. Earum et excepturi animi ex esse accusantium et. Id adipisci eos enim
|
|
||||||
ratione.
|
|
||||||
|
|
||||||
## options
|
|
||||||
|
|
||||||
back: start
|
|
||||||
to node 2: node2
|
|
||||||
run foo (rerun node): foo()
|
|
||||||
customnode: Go to custom node -> customnode
|
|
||||||
>: return to go back -> start
|
|
||||||
|
|
||||||
# node node2
|
|
||||||
|
|
||||||
In node 2!
|
|
||||||
|
|
||||||
## options
|
|
||||||
|
|
||||||
back: back to start -> start
|
|
||||||
|
|
||||||
|
|
||||||
# node bar
|
|
||||||
|
|
||||||
In node bar!
|
|
||||||
|
|
||||||
## options
|
|
||||||
|
|
||||||
back: back to start -> start
|
|
||||||
end: end
|
|
||||||
|
|
||||||
# node end
|
|
||||||
|
|
||||||
In node end!
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
callables = {"gotonode3": gotonode3, "foo": foo, "bar": bar}
|
|
||||||
dct = parse_menu_template(caller, MENU_TEMPLATE, callables)
|
|
||||||
dct["customnode"] = customnode
|
|
||||||
|
|
||||||
EvMenu(caller, dct)
|
|
||||||
|
|
||||||
|
|
||||||
# template2menu(caller, MENU_TEMPLATE, callables)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
test_generator("<GriatchCaller>")
|
|
||||||
174
evennia/contrib/tutorial_world/tutorialmenu.py
Normal file
174
evennia/contrib/tutorial_world/tutorialmenu.py
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
"""
|
||||||
|
Game tutor
|
||||||
|
|
||||||
|
Evennia contrib - Griatch 2020
|
||||||
|
|
||||||
|
This contrib is a tutorial menu using the EvMenu menu-templating system.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from evennia.utils.evmenu import parse_menu_template, EvMenu
|
||||||
|
|
||||||
|
# goto callables
|
||||||
|
|
||||||
|
def command_passthrough(caller, raw_string, **kwargs):
|
||||||
|
cmd = kwargs.get("cmd")
|
||||||
|
on_success = kwargs.get('on_success')
|
||||||
|
if cmd:
|
||||||
|
caller.execute_cmd(cmd)
|
||||||
|
else:
|
||||||
|
caller.execute_cmd(raw_string)
|
||||||
|
return on_success
|
||||||
|
|
||||||
|
def do_nothing(caller, raw_string, **kwargs):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def send_testing_tagged(caller, raw_string, **kwargs):
|
||||||
|
caller.msg(("This is a message tagged with 'testing' and "
|
||||||
|
"should appear in the pane you selected!\n "
|
||||||
|
f"You wrote: '{raw_string}'", {"type": "testing"}))
|
||||||
|
return None
|
||||||
|
|
||||||
|
def send_string(caller, raw_string, **kwargs):
|
||||||
|
caller.msg(raw_string)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
MENU_TEMPLATE = """
|
||||||
|
|
||||||
|
## NODE start
|
||||||
|
|
||||||
|
Welcome to |cEvennia|n! From this menu you can learn some more about the system and
|
||||||
|
also the basics of how to play a text-based game. You can exit this menu at
|
||||||
|
any time by using "q" or "quit".
|
||||||
|
|
||||||
|
Select an option you want to learn more about below.
|
||||||
|
|
||||||
|
## OPTIONS
|
||||||
|
|
||||||
|
1: About evennia -> about_evennia
|
||||||
|
2: What is a MUD/MU*? -> about_muds
|
||||||
|
3: Using the webclient -> using webclient
|
||||||
|
4: Command input -> command_input
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## NODE about_evennia
|
||||||
|
|
||||||
|
Evennia is a game engine for creating multiplayer online text-games.
|
||||||
|
|
||||||
|
## OPTIONS
|
||||||
|
|
||||||
|
back: start
|
||||||
|
next: about MUDs -> about_muds
|
||||||
|
>: about_muds
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## NODE about_muds
|
||||||
|
|
||||||
|
The term MUD stands for Multi-user-Dungeon or -Dimension. These are the precursor
|
||||||
|
to graphical MMORPG-style games like World of Warcraft.
|
||||||
|
|
||||||
|
|
||||||
|
## OPTIONS
|
||||||
|
|
||||||
|
back: about_evennia
|
||||||
|
next: using the webclient -> using webclient
|
||||||
|
back to top: start
|
||||||
|
>: using webclient
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## NODE using webclient
|
||||||
|
|
||||||
|
Evennia supports traditional telnet clients but also offers a HTML5 web client. It
|
||||||
|
is found (on a default install) by pointing your web browser to
|
||||||
|
|yhttp:localhost:4001/webclient|n
|
||||||
|
For a live example, the public Evennia demo can be found at
|
||||||
|
|yhttps://demo.evennia.com/webclient|n
|
||||||
|
|
||||||
|
The web client start out having two panes. The bottom one is where you insert commands
|
||||||
|
and the top one is where you see returns from the server.
|
||||||
|
|
||||||
|
- Use |y<Return>|n (or click the arrow on the right) to send your input.
|
||||||
|
- Use |yCtrl + <up-arrow>|n to step back and repeat a command you entered previously.
|
||||||
|
- Use |yCtrl + <Return>|n to add a new line to your input without sending.
|
||||||
|
|
||||||
|
If you want there is some |wextra|n info to learn about customizing the webclient.
|
||||||
|
|
||||||
|
## OPTIONS
|
||||||
|
|
||||||
|
back: about_muds
|
||||||
|
extra: learn more about customizing the webclient -> customizing the webclient
|
||||||
|
next: general command input -> command_input
|
||||||
|
back to top: start
|
||||||
|
>: back
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## NODE customizing the webclient
|
||||||
|
|
||||||
|
|y1)|n The panes of the webclient can be resized and you can create additional panes.
|
||||||
|
|
||||||
|
- Press the little plus (|w+|n) sign in the top left and a new tab will appear.
|
||||||
|
- Click and drag the tab and pull it far to the right and release when it creates two
|
||||||
|
panes next to each other.
|
||||||
|
|
||||||
|
|y2)|n You can have certain server output only appear in certain panes.
|
||||||
|
|
||||||
|
- In your new rightmost pane, click the diamond (⯁) symbol at the top.
|
||||||
|
- Unselect everything and make sure to select "testing".
|
||||||
|
- Click the diamond again so the menu closes.
|
||||||
|
- Next, write "|ytest Hello world!|n". A test-text should appear in your rightmost pane!
|
||||||
|
|
||||||
|
|y3)|n You can customize general webclient settings by pressing the cogwheel in the upper
|
||||||
|
left corner. It allows to change things like font and if the client should play sound.
|
||||||
|
|
||||||
|
The "message routing" allows for rerouting text matching a certain regular expression (regex)
|
||||||
|
to a web client pane with a specific tag that you set yourself.
|
||||||
|
|
||||||
|
|y4)|n Close the right-hand pane with the |wX|n in the rop right corner.
|
||||||
|
|
||||||
|
## OPTIONS
|
||||||
|
|
||||||
|
back: using webclient
|
||||||
|
next: general command input -> command_input
|
||||||
|
back to top: start
|
||||||
|
> test *: send tagged message to new pane -> send_testing_tagged()
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## NODE command_input
|
||||||
|
|
||||||
|
The first thing to learn is to use the |yhelp|n command.
|
||||||
|
|
||||||
|
## OPTIONS
|
||||||
|
|
||||||
|
back: using webclient
|
||||||
|
next: (end) -> end
|
||||||
|
back to top: start
|
||||||
|
> h|help: command_passthrough(cmd=help)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## NODE end
|
||||||
|
|
||||||
|
Thankyou for going through the tutorial!
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
GOTO_CALLABLES = {
|
||||||
|
"command_passthrough": command_passthrough,
|
||||||
|
"send_testing_tagged": send_testing_tagged,
|
||||||
|
"do_nothing": do_nothing,
|
||||||
|
"send_string": send_string,
|
||||||
|
}
|
||||||
|
|
||||||
|
def testmenu(caller):
|
||||||
|
menutree = parse_menu_template(caller, MENU_TEMPLATE, GOTO_CALLABLES)
|
||||||
|
# we'll use a custom EvMenu child later
|
||||||
|
EvMenu(caller, menutree, auto_help=False)
|
||||||
|
|
||||||
|
|
@ -1584,7 +1584,7 @@ def get_input(caller, prompt, callback, session=None, *args, **kwargs):
|
||||||
#
|
#
|
||||||
# -------------------------------------------------------------
|
# -------------------------------------------------------------
|
||||||
|
|
||||||
_RE_NODE = re.compile(r"##\s*?NODE\s+?(?P<nodename>\S+?)$", re.I + re.M)
|
_RE_NODE = re.compile(r"##\s*?NODE\s+?(?P<nodename>\S[\S\s]*?)$", re.I + re.M)
|
||||||
_RE_OPTIONS_SEP = re.compile(r"##\s*?OPTIONS\s*?$", re.I + re.M)
|
_RE_OPTIONS_SEP = re.compile(r"##\s*?OPTIONS\s*?$", re.I + re.M)
|
||||||
_RE_CALLABLE = re.compile(r"\S+?\(\)", re.I + re.M)
|
_RE_CALLABLE = re.compile(r"\S+?\(\)", re.I + re.M)
|
||||||
_RE_CALLABLE = re.compile(
|
_RE_CALLABLE = re.compile(
|
||||||
|
|
@ -1650,7 +1650,7 @@ def _generated_input_goto_func(caller, raw_string, **kwargs):
|
||||||
return goto, {"generated_nodename": goto}
|
return goto, {"generated_nodename": goto}
|
||||||
# no glob pattern match; try regex
|
# no glob pattern match; try regex
|
||||||
for pattern, goto in gotomap.items():
|
for pattern, goto in gotomap.items():
|
||||||
if re.match(pattern, raw_string.lower(), flags=re.I + re.M):
|
if pattern and re.match(pattern, raw_string.lower(), flags=re.I + re.M):
|
||||||
if _RE_CALLABLE.match(goto):
|
if _RE_CALLABLE.match(goto):
|
||||||
gotofunc = goto.strip()[:-2]
|
gotofunc = goto.strip()[:-2]
|
||||||
if gotofunc in goto_callables:
|
if gotofunc in goto_callables:
|
||||||
|
|
@ -1748,6 +1748,7 @@ def parse_menu_template(caller, menu_template, goto_callables=None):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
print(f"nodename: {nodename}, options: {options}")
|
||||||
return options
|
return options
|
||||||
|
|
||||||
def _parse(caller, menu_template, goto_callables):
|
def _parse(caller, menu_template, goto_callables):
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
let goldenlayout = (function () {
|
let goldenlayout = (function () {
|
||||||
|
|
||||||
var myLayout;
|
var myLayout;
|
||||||
var knownTypes = ["all", "untagged"];
|
var knownTypes = ["all", "untagged", "testing"];
|
||||||
var untagged = [];
|
var untagged = [];
|
||||||
|
|
||||||
var newTabConfig = {
|
var newTabConfig = {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue