!7 concept Cmd { S patterns; // for mmo_parsePattern S cmd; // a pattern recognized by #1027443 int index; transient MMOPattern parsedPattern; void change { parsedPattern = null; super.change(); } MMOPattern parsedPattern() { if (parsedPattern == null) parsedPattern = mmo_parsePattern(patterns); ret parsedPattern; } sS _fieldOrder = "patterns cmd index"; } cmodule ScenariosFrontend > DynCRUD { S backendModuleLibID = "#1027443/Scenarios"; O currentAttractor; transient Map argumentsForCommands = litcimap( "new scenario *", ll("What is the name of the new scenario?"), "delete scenario *", ll("Which scenario would you like to delete?"), "rename scenario * to *", ll( "Which scenario would you like to rename?", "What is the new name for the scenario?") ); class HandleArgument implements IF1 { S cmd; LS arguments; *() {} *(S *cmd) {} // process an argument S get(S arg) { arguments.add(arg); if (l(arguments) >= countAsteriskTokens(cmd)) ret sendToBackend(format_quoteAll(cmd, arguments)); else ret handleQuestionWithArguments(this); } S currentQuestion() { LS argQuestions = argumentsForCommands.get(cmd); ret or2(_get(argQuestions, l(arguments)), "Need argument"); } } S handleCommand(Cmd cmd) { if (cmd == null) null; print("handleCommand " + cmd.cmd); if (hasAsteriskTokens(cmd.cmd)) ret handleQuestionWithArguments(new HandleArgument(cmd.cmd)); else ret sendToBackend(cmd.cmd); } S handleQuestionWithArguments(HandleArgument handler) { new WaitForName attractor; attractor.question = handler.currentQuestion(); setField(currentAttractor := attractor); attractor.processName = handler; ret attractor.question; } S sendToBackend(S cmd) { ret (S) dm_call(getBackend(), 'answer, cmd); } S getBackend() { ret dm_require(backendModuleLibID); } afterVisualize { addComponent(crud.buttons, jbutton("Talk to me", rThread talkToMe)); } void talkToMe enter { dm_showConversationPopupForModule(); } // API void copyCommandsFromBackend() { for (S cmd : allIfQuotedPatterns(loadSnippet(#1027443))) uniqConcept(+cmd); } S answer(S s) { try answer (S) call(currentAttractor, 'answer, s); ret handleCommand(mmo_matchMultiWithTypos(1, filter(conceptsSortedByField Cmd('index), c -> nempty(c.patterns)), c -> c.parsedPattern(), s)); } }