!7 set flag DynModule. // for evals set flag JDA40. cmodule Gazelle2 > DynDiscordHopper { switchable S myName = "Gazelle"; void init after super { dm_vmBus_onMessage_q editedDiscordMessage(voidfunc(Map map) { ret if !enabled || !dm_isMe(map.get('module)); ret if isTrue(map.get('bot)); S s = getString content(map); Message msg = cast map.get('msg); long msgID = getLong msgID(map); MessageChannel channel = cast map.get('channel); long userID = getLong userID(map); print("Got edited message: " + s); // experimental edited msg handling for evals if (startsWith(s, "!")) { // postInChannel(channel, "I saw your edit, " + discordAt(userID)); RecordedAnswer oldAnswer = firstWhere(recordedAnswers, questionMsgID := msgID); print("Have " + n2(recordedAnswers, "recorded answer") + ", found " + oldAnswer); if (oldAnswer != null) { recordedAnswers.remove(oldAnswer); change(); pcall { print("Deleting my old answer: " + oldAnswer.answerMsgID); discord.getTextChannelById(oldAnswer.channelID) .deleteMessageById(oldAnswer.answerMsgID).queue(); } } S answer = answer(s, map); sendReply(map, answer); } }); } transient new InheritableThreadLocal msgMap; // while answering @Override S answer(S s, Map map) { new Matches m; temp tempSetTL(msgMap, map); long ch = getLong channelID(map); long userID = getLong userID(map); S sOld = s; s = dropPrefix_trim(atSelf() + " ", s); if (sOld != s) print("dropped atSelf >> " + s); s = simpleSpaces_javaTok(s); if (match("help", s) || match(myName + " help", s)) ret linesLL( atSelf() + " source - show sources", myName + ", show me X - show an image", myName + ", look up X - dictionary lookup", "what's your name - say my name", "!eval 1+2 - evaluate JavaX code" ); if (eqicOneOf(s, "source", "sources", "source code")) ret snippetLink(programID()); if "what's your name" ret myName; if (swic_trim(s, myName + ", show me ", m)) { iAmTyping(map); S query = m.rest(); BufferedImage img = quickVisualize(query); if (img == null) ret "No image found, sorry!"; postImage(map, dehttps(uploadToImageServer(img, query))); null; } if (swic_trim(s, myName + ", look up ", m)) { if (isSingleWord($1)) try answer wordNet_pretty($1); ret ":cry: I don't know"; } if (ellipsisToDotStarRegexpFindIC("days...year", collapse(s))) ret nDays(daysUntilEndOfYear()) + " till end of year"; S content = s; try { if (swicOneOf(content, "!eval ", "!fresh ", "!real-eval", "!safe-eval ") || eqic(content, "!fresh")) { O safetyCheck = null; bool authed = dm_discord_userCanEval(userID); print("Authed " + userID + " => " + authed); if (swic_trim(content, "!safe-eval ", m)) { content = "!eval " + m.rest(); authed = false; } /*if (regexpMatches("![a-z\\-]+\\s+again", content)) { GazelleLine last = dm_discord_nextToLastEvalByUser(userID); if (last == null) ret "No last eval found"; content = replaceSuffix("again", afterSpace(last.text), content); }*/ if (!authed) safetyCheck = botEval_strictSafetyCheck(); iAmTyping(map); dm_mediumRefreshTranspiler(); dm_bot_execEvalCmd(voidfunc(S s) { if (s != null) sendReply(map, shorten(ifEmpty(s, [[""]]), 1000)); }, content, +safetyCheck); null; } } catch print error { postInChannel(ch, exceptionToStringShort(error)); } ret super.answer(s, map); } // for evals with gazelle_msg() Message respondingTo() { ret (Message) get msg(msgMap!); } MessageChannel currentChannel() { ret (MessageChannel) get channel(msgMap!); } void postImage(S url) { postImage(msgMap!, url); } void postImage(S url, S description) { postImage(msgMap!, url, description); } }