!759 static Map theories; // lower case name -> text static new MultiMap signMap; p { theories2 = new PersistentMap("theories2"); if (theories2.isEmpty()) { Map theoriesOld = new PersistentMap("theories"); for (S name : keys(theoriesOld)) theories.put(name.toLowerCase(), theoriesOld.get(name)); } load("signMap"); } static synchronized L getTheoryNames() { ret new ArrayList(theories.keySet()); } static synchronized boolean hasTheory(S name) { ret theories.containsKey(name.toLowerCase()); } static synchronized S getTheoryOpt(S name) { ret theories.get(name.toLowerCase()); } static synchronized S getTheory(S name) { S text = getTheoryOpt(name); if (text == null) fail("Theory * not found", name); ret text; } static synchronized L getTheoriesSignedBy(S user) { ret signMap.reverseGet(user); } static synchronized void addTheory(S name, S text) { if (hasTheory(name)) fail("Theory * exists", name); theories.put(name, text); } synchronized answer { //if (!attn()) ret null; if "count theories" ret l(theories); if "list theories" ret structure(keys(theories)); if "show theory *" exceptionToUser { ret showTheories(litlist(m.unq(0))); } if (matchStart("show theories", s, m)) exceptionToUser { ret showTheories(codeTokensOnly(javaTok(m.rest()))); } if "modify theory * *" exceptionToUser { S name = m.unq(0), text = m.unq(1); ret saveTheory(name, text); } if "add theory * *" exceptionToUser { S name = m.unq(0), text = m.unq(1); addTheory(name, text); //boolean parses = doesTheoryParse(name); //ret format(parses ? "OK, added theory *" : "Added theory *. Warning: Doesn't parse", name); ret format("OK, added theory *", name); } if "sign theory *" exceptionToUser { S user = getUserName(); if (empty(user)) ret "go to slack please"; S name = m.unq(0); if (!hasTheory(name)) ret "Theory not found"; L users = signMap.get(name); if (users.contains(user)) ret "You have already signed this theory!"; signMap.put(name, user); save("signMap"); ret "OK, signed! All signers: " + structure(signMap.get(name)); } if "unsign theory *" exceptionToUser { S user = getUserName(); if (empty(user)) ret "go to slack please"; S name = m.unq(0); L users = signMap.get(name); if (!users.contains(user)) { if (!hasTheory(name)) ret "Theory not found"; ret "You have not signed this theory."; } signMap.remove(name, user); save("signMap"); ret "OK, unsigned! Remaining signers: " + structure(signMap.get(name)); } if "my signed theories" exceptionToUser { S user = getUserName(); if (empty(user)) ret "go to slack please"; ret structure(signMap.reverseGet(user)); } if "theories signed by *" exceptionToUser { S user = m.unq(0); ret structure(signMap.reverseGet(user)); } if (match("theories page", s) || match("theories url", s)) ret getBotURL(); if (!master()) ret null; if "delete theory *" exceptionToUser { S name = toLowerCase(m.unq(0)); if (hasTheory(name)) { S text = theories.get(name); logMap("deleted", "name", name, "text", text, "time", now(), "signers", signMap.get(name)); logMap("deleted", "name", name, "signers", signMap.get(name)); theories.remove(name); signMap.remove(name); save("signMap"); ret format("Theory * backed up & deleted", name); } else ret format("Theory * not found", name); } if "rename theory * to *" exceptionToUser { S name = toLowerCase(m.unq(0)), newName = toLowerCase(m.unq(1)); if (hasTheory(newName)) ret format("A theory named * already exists", newName); if (hasTheory(name)) { S text = theories.get(name); theories.put(newName, text); theories.remove(name); // update signMap L signers = signMap.get(name); signMap.addAll(newName, signers); signMap.remove(name); save("signMap"); ret format("Theory * renamed to *", name, newName); } else ret format("Theory * not found", name); } } static S showTheories(L theoryNames) { new StringBuilder buf; for (S name: theoryNames) { if (!hasTheory(name)) buf.append(format("Theory * not found\n", name)); else { //boolean parses = doesTheoryParse(name); buf.append(quote(name) /* + " (" + (parses ? "PARSES" : "DOES NOT PARSE") + ")\n"*/ + "\n" + slackSnippet(theories.get(name)) + "\n\n"); } } ret str(buf).trim(); } static S html() { new L data; for (S name : theories.keySet()) { S text = unnull(theories.get(name)); boolean multi = false; Exception error = null; try { multi = nlIsMultipleStatements(text); } catch (Exception e) { error = e; } Map map = litmap( "Name", htmlencode(name), "Theory", pre(htmlencode(minitrim(rtrim(text)))), "Signed by", htmlencode(structure(signMap.get(name))), "Multiple rules?", multi); if (error != null) map.put("Parse Error", str(error)); data.add(map); } ret h3("Theories!") + htmlTable(data, false); } // preserves formatting of first line static S minitrim(S s) { L l = toLines(s); while (!empty(l) && empty(trim(first(l)))) l.remove(0); ret autoUnindent(fromLines(l)); } static S saveTheory(S name, S text) { boolean has = hasTheory(name); logMap(has ? "modified" : "added", "name", name, "text", text, "time", now()); theories.put(name, text); ret format((has ? "OK, modified theory *" : "OK, added theory *"), name); }