Mercurial Hosting > nabble
view src/nabble/view/web/template/MacroEditorNamespace.java @ 0:7ecd1a4ef557
add content
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Thu, 21 Mar 2019 19:15:52 -0600 |
parents | |
children |
line wrap: on
line source
package nabble.view.web.template; import fschmidt.util.java.HtmlUtils; import nabble.model.Site; import nabble.modules.ModuleManager; import nabble.naml.compiler.Command; import nabble.naml.compiler.CommandSpec; import nabble.naml.compiler.CompileException; import nabble.naml.compiler.IPrintWriter; import nabble.naml.compiler.Interpreter; import nabble.naml.compiler.Macro; import nabble.naml.compiler.Meaning; import nabble.naml.compiler.Namespace; import nabble.naml.compiler.Program; import nabble.naml.compiler.Source; import nabble.naml.compiler.Usage; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @Namespace( name = "macro_editor", global = false ) public class MacroEditorNamespace { private Site site; private String rootMacroName; private String[] baseClassArray; private final Macro macro; private static class SaveResults { String error; String macroId; String base; String breadcrumbs; } public MacroEditorNamespace(Site site, String meaningId, String base, String breadcrumbs) { this.site = site; this.baseClassArray = MacroSourceNamespace.buildBaseClassArray(base); this.rootMacroName = getRootMacroName(site.getProgram(), meaningId, base, breadcrumbs); if (meaningId == null) { macro = null; } else { Meaning meaning = site.getProgram().getMeaning(meaningId); if (meaning == null) throw new NullPointerException("Meaning is null for: " + meaningId); else if (!(meaning instanceof Macro)) throw new NullPointerException("Meaning is not a macro: " + meaningId); macro = (Macro) meaning; } } private String getRootMacroName(Program program, String meaningId, String base, String breadcrumbs) { if (breadcrumbs != null) { String firstMeaningId = breadcrumbs.split("-")[0]; Meaning meaning = program.getMeaning(firstMeaningId); return meaning.getName(); } else if (base != null && meaningId != null) { return program.getMeaning(meaningId).getName(); } return null; } public static final CommandSpec CONTENTS = new CommandSpec.Builder() .parameters("contents") .build(); public static final CommandSpec save = CONTENTS; @Command public void save(IPrintWriter out, Interpreter interp) { String tweak = getContents(interp); Map<String, String> originalTweaks = site.getCustomTweaks(); Map<String, String> newTweaks = new HashMap<String, String>(originalTweaks); if (isEditingCustomTweak()) { String macroBody = macro.element.toString(); for( Map.Entry<String,String> entry : originalTweaks.entrySet() ) { String filename = entry.getKey(); String content = entry.getValue(); int posStart = content.indexOf(macroBody); if (posStart >= 0) { SaveResults saveResults = saveTweak(tweak, originalTweaks, newTweaks, filename); out.print(HtmlUtils.toJson(saveResults)); return; } } } else { String macroName = getMacroName(macro, tweak); if (macroName == null) { out.print("Error: You must specify the name of the macro."); return; } // tries to find a file with the name of the macro String file = newTweaks.get(macroName); String newFileContents = file == null? tweak : file + "\n\n" + tweak; SaveResults saveResults = saveTweak(newFileContents, originalTweaks, newTweaks, macroName); out.print(HtmlUtils.toJson(saveResults)); } } private SaveResults saveTweak(String tweak, Map<String, String> originalTweaks, Map<String, String> newTweaks, String filename) { SaveResults saveResults = new SaveResults(); try { Usage usage = saveAndCheck(newTweaks, filename, tweak); saveResults.macroId = getMacroId(filename, tweak); // If usage is not null, then it was found while saving the tweak. // We send this information back to the page so that the javascript // can send the user to a page with navigation links. if (usage != null) { saveResults.base = MacroSourceNamespace.asBaseParam(usage.baseIds()); saveResults.breadcrumbs = MacroSourceNamespace.asBreadcrumbsParam(usage.macroPath()) ; } } catch(CompileException e) { site.setCustomTweaks(originalTweaks); saveResults.error = "Error: " + e.getMessage(); } return saveResults; } private String getMacroName(Macro macro, String tweak) { if (macro != null) return macro.getName(); else { Pattern pattern = Pattern.compile("name=\"([^\"]+)\""); Matcher matcher = pattern.matcher(tweak); if (matcher.find()) return matcher.group(1); else return null; } } private Usage saveAndCheck(Map<String, String> newTweaks, String filename, String newFileContents) throws CompileException { newFileContents = trim(newFileContents); newTweaks.put(filename, newFileContents); boolean isCompiledMacro = macro != null && site.getProgram().isCompiled(macro); site.setCustomTweaks(newTweaks); if (rootMacroName != null) { try { // Tries to compile the macro site.getProgram().getTemplate(rootMacroName, this.baseClassArray); } catch (CompileException e) { if (isCompiledMacro) throw e; else { Program program = site.getProgram(); // Let's try to find a usage for this macro for a better check if (!NabbleNamespace.isCompiledAll(program)) CompileTest.compileAll(program); Meaning m = program.getMeaning(macro.getId()); Set<Usage> usages = program.getUsages(m); if (usages == null || usages.size() == 0) throw e; else { Usage usage = usages.iterator().next(); program.getTemplate(usage.macroPath().get(0).getName(), usage.baseIds()); return usage; } } } } else { // Simple XML validation site.getProgram().getTemplate("do_nothing"); } return null; } private String getMacroId(String filename, String macroBody) throws CompileException { Program program = site.getProgram(); if (macro != null && program.getMeaning(macro.getId()) != null) return macro.getId(); Macro m = program.getMacroWhichOverrides(macro); if (m != null) return m.getId(); List<Source> sources = site.getProgram().getSources(); for (Source s : sources) { if (s.id.contains(':'+filename)) { for (Macro mac : s.getMacros()) { if (macroBody.contains(mac.element.toString())) return mac.getId(); } } } throw new RuntimeException("macroId not found"); } public static final CommandSpec revert = CommandSpec.NO_OUTPUT; @Command public void revert(IPrintWriter out,Interpreter interp) { if (isEditingCustomTweak()) { String macroBody = macro.element.toString(); Map<String, String> tweaks = site.getCustomTweaks(); Map<String, String> reverted = new HashMap<String, String>(tweaks); for( Map.Entry<String,String> entry : tweaks.entrySet() ) { String name = entry.getKey(); String content = entry.getValue(); int posStart = content.indexOf(macroBody); if (posStart >= 0) { int posEnd = posStart + macroBody.length(); String revertedContents = content.substring(0, posStart) + "\n" + content.substring(posEnd); if (trim(revertedContents).length() == 0) reverted.remove(name); else reverted.put(name, revertedContents); site.setCustomTweaks(reverted); break; } } } else throw new RuntimeException("Not a tweaked macro"); } private String getContents(Interpreter interp) { String c = interp.getArgString("contents"); c = c.replaceAll("\\u2002", " "); // Converts any   into simple space (copy and paste issue) return c; } private String trim(String s) { return s.replaceAll("(^\\s+)|(\\s+$)",""); } private boolean isEditingCustomTweak() { return macro != null && ModuleManager.isCustomTweak(macro.source); } }