// Some of the functions are dependent on the concepts field, // others are global. sclass G22Utils_Base { // event that is triggered every time a file or directory inside the // project changes. Starts the fileWatcher automatically when the // first listener is added. event projectFileChanged(File file); } sclass G22Utils > G22Utils_Base is AutoCloseable, TransientObject { settable IBackgroundProcesses backgroundProcessesUI; settable Enterable module; settable G22MasterStuff masterStuff; settable Concepts concepts; settable G22ProjectActions projectActions; gettable G22AutoStarter autoStarter = new(this); settable new FunctionTimings functionTimings; FileWatchService fileWatcher; // general file watch service bool projectFileListenerInitiated; gettable CombinedStringifier stringifier = new( o -> o cast BufferedImage ? "Image (" + o.getWidth() + "*" + o.getHeight() + " px)" : null ); ILASClassLoader lasClassLoader() { ret masterStuff?.lasClassLoader(); } ImageSurface stdImageSurface() { var is = pixelatedImageSurface().setAutoZoomToDisplay(true).repaintInThread(false); is.defaultImageDir = -> dbDir(); is.specialPurposed = true; new ImageSurface_PositionToolTip(is); ret is; } ImageSurface stdImageSurface(BufferedImage etc img) { var is = stdImageSurface(); is.setImage(img); ret is; } ImageSurface stdImageSurfaceWithSelection(BufferedImage etc img, Rect selection) { var is = stdImageSurface(img); is.setSelection(selection); ret is; } S stringify(O o) { ret stringifier.toString(o); } event settingUpParser(GazelleV_LeftArrowScriptParser parser); event settingUpScriptIDE(JLeftArrowScriptIDE ide); GazelleV_LeftArrowScriptParser leftArrowParser() { new GazelleV_LeftArrowScriptParser parser; parser.classNameResolver(classNameResolver()); parser.lasClassLoader(lasClassLoader()); settingUpParser(parser); parser.addClassAlias("Freq", "Frequency"); ret parser; } void basicParserTest() { var parser = leftArrowParser(); print(classContainerPrefixes := parser.classContainerPrefixes()); assertEquals(pair(1, 2), parser.parse("new Pair 1 2")!); } ifclass JLeftArrowScriptIDE JLeftArrowScriptIDE leftArrowIDE() { new JLeftArrowScriptIDE ide; ide.g22utils(this); ide.scriptTimeout(projectWideScriptTimeout()); settingUpScriptIDE(ide); ret ide; } endif File byteCodePath() { ret assertNotNull(getBytecodePathForClass(this)); } simplyCached ClassNameResolver classNameResolver() { ret new ClassNameResolver().byteCodePath(byteCodePath()).init(); } File databasesMotherDir() { ret javaxDataDir("Gazelle-22"); } File dirOfProjectNamed(S name) { assertNempty(name); ret newFile(databasesMotherDir(), name); } AutoCloseable enter() { ret module?.enter(); } S defaultDBName() { ret "Default"; } File lastOpenedDBsFile() { ret newFile(databasesMotherDir(), "Last Opened"); } File autoUpdateFile() { ret newFile(databasesMotherDir(), "Auto-Update"); } bool autoUpdateEnabled() { ret fileExists(autoUpdateFile()); } void setAutoUpdate(bool b) { createOrRemoveFile(autoUpdateFile(), b); } LS dbsToOpen() { new LS dbNames; for (S name : tlft(loadTextFile(lastOpenedDBsFile()))) if (fileExists(newFile(databasesMotherDir(), name))) dbNames.add(name); if (empty(dbNames)) dbNames.add(defaultDBName()); ret dbNames; } void setOpenDBs(Cl dbDirs) { new LS dbNames; for (File dbDir : dbDirs) if (sameFile(databasesMotherDir(), dirOfFile(dbDir))) dbNames.add(fileName(dbDir)); saveTextFile(lastOpenedDBsFile(), lines(dbNames)); } ifclass SimpleCRUD_v2 void setupScriptCRUD(SimpleCRUD_v2 crud, bool allowRunOnProjectOpen default false) { crud.useNewChangeHandler(true); crud.editableFieldsForItem = x -> llNonNulls("description", allowRunOnProjectOpen ? "runOnProjectOpen" : null, allowRunOnProjectOpen ? "runOrder" : null); //G22LeftArrowScript.f_description().getName()); crud.multiLineField("text"); crud.multiLineField("editingText"); crud.makeTextArea = text -> jMinHeight(200, crud.makeTextArea_base(text)); crud.humanizeFieldNames = false; crud.iconButtons(true); crud.itemToMap_inner2 = c -> scriptToMap(c, allowRunOnProjectOpen); } endif MapSO scriptToMap(G22LeftArrowScript c, bool allowRunOnProjectOpen default false) { ret litorderedmap( "Description" := str(c), "Status" := renderScriptStatus(c), "LoC" := renderScriptLoC(c), "Run on project open" := c.renderRunOnProjectOpenStatus()); } S renderScriptStatus(G22LeftArrowScript c) { ret or2_rev("Empty", joinNemptiesWithSpacedPlus( c.isClearForAutoRun() ? "Clear for auto-run" : null, c.isSavedDistinctFromAutoRunVersion() ? "Saved (not cleared)" : null, c.isEditing() ? "Editing" : null )); } S renderScriptLoC(G22LeftArrowScript c) { ret n2(intMax(mapLL linesOfCode_javaTok( c.editingText, c.text, c.codeForAutoRun()))); } // e.g. for an image file L labelsForFile(File file) { if (file == null) null; File labelsFile = appendToFileName(file, ".labels"); LS labels = tlft(loadTextFile(labelsFile)); ret map getLabel(labels); } File labelsFile(File file) { if (file == null) null; ret appendToFileName(file, ".labels"); } void setLabelsForFile(File file, L labels) { LS list = map(labels, label -> label.name); File f = labelsFile(file); saveTextFile(f, lines(list)); print("Saved " + nLabels(list) + " (" + joinWithComma(list) + ") to " + f); } G22Label getLabel(S name) { if (empty(name)) null; if (containsNewLine(name)) fail("No newlines in label names allowed: " + name); ret uniqCI(concepts, G22Label, +name); } File dbDir aka projectDir() { ret conceptsDir(concepts); } File fileInDbDir aka projectFile(S name) { ret newFile(dbDir(), name); } record GazelleDB(S name, File dir) { S name() { ret name; } File dir() { ret dir; } simplyCached bool loaded() { ret containsFile(masterStuff.openConceptDirs(), dir); } File conceptsFile() { ret conceptsFileIn(dir); } } L gazelleDBs() { new L dbs; for (File dir : listDirsContainingFileNamed(databasesMotherDir(), "concepts.structure.gz")) dbs.add(new GazelleDB(fileName(dir), dir)); ret dbs; } ifclass RSyntaxTextAreaWithSearch RSyntaxTextAreaWithSearch newSyntaxTextArea(IF1 wrapStatusLabel default (IF1) null) { RSyntaxTextAreaWithSearch ta = new(wrapStatusLabel); ta.textArea().setHighlightCurrentLine(false); ta.menuLessOperation(); ret ta; } RSyntaxTextAreaWithSearch newSyntaxTextArea(S text) { var ta = newSyntaxTextArea(); ta.setText(text); ret ta; } endif File projectStoryTextFile() { ret newFile(dbDir(), "story.txt"); } S projectName() { ret fileName(dbDir()); } close { autoStarter.close(); dispose fileWatcher; } // project vars G22Variable findProjectVar(S name) { ret conceptWhere(concepts, G22Variable, +name); } O getProjectVar(S name) { G22Variable var = findProjectVar(name); ret var?.value; } O waitForProjectVar(S name) { G22Variable var = optimizedUniq(concepts, G22Variable, +name); O o = var.value; try object o; ret waitUntilNotNull(var.varValue()); } void setProjectVar(bool persistent, S name, O value) { G22Variable var = optimizedUniq(concepts, G22Variable, +name); // defensive order if (!persistent) var.persistent(persistent); var.value(value); if (persistent) var.persistent(persistent); } void setTransientProjectVar(S name, O value) { G22Variable var = optimizedUniq(concepts, G22Variable, +name); var.persistent(false).value(value); } void deleteProjectVar(S name) { deleteConcept(findProjectVar(name)); } // variable is made persistent IVarWithNotify liveProjectVar(S name, O defaultValue default null) { G22Variable var = optimizedUniq(concepts, G22Variable, +name); var.persistent(true); var.setValueIfNull(defaultValue); ret var.varValue(); } IVarWithNotify liveTransientProjectVar(S name, O defaultValue default null) { G22Variable var = optimizedUniq(concepts, G22Variable, +name); var.persistent(false); var.setValueIfNull(defaultValue); ret var.varValue(); } void replaceCloseableProjectVar(S name, IF0 calc) { O value = getProjectVar(name); if (value cast AutoCloseable) { main close(value); deleteProjectVar(name); } setTransientProjectVar(name, calc?!); } // timeouts double defaultScriptTimeout() { ret 10.0; } double projectWideScriptTimeout() { ret or(toDoubleOrNull(getProjectVar("!Script Timeout")), defaultScriptTimeout()); } // getting objects G22Analyzer getAnalyzer(long id) { var a = getConcept(concepts, G22Analyzer, id); if (a == null) fail("Analyzer not found: " + id); ret a; } G22LeftArrowScript getScript(long id) { var a = getConcept(concepts, G22LeftArrowScript, id); if (a == null) fail("Script not found: " + id); ret a; } // calling scripts // This is meant to be called from within another script. // No timeout (timeout is handled by calling script) // Uses "safest" version available (auto-run or saved) O callScript(long id) { var script = getScript(id); ret script.evaluateWithoutTimeout(); } // Like callScript, but only uses auto-run version O callAutoRunnableScript(long id) { var script = getScript(id); ret script.evaluateAutoRunWithoutTimeout(); } // no timeout by default double defaultTimeout() { ret infinity(); } // evaluate // -with timeout // -registered in background processes // -with module entered A evalRegisteredCode(double timeoutSeconds default defaultTimeout(), S processName, IF0 code) { if (code == null) null; ret evalWithTimeoutOrTypedException(timeoutSeconds, -> { temp enter(); temp var process = backgroundProcessesUI.tempAdd(processName); Thread myThread = currentThread(); process.setInterruptAction(r { cancelThread(myThread) }); ret code!; }); } virtual GazelleHost host() { temp enter(); ret dm_os(); } A timeFunction(S name, IF0 f) { ret functionTimings.get(name, f); } bool isConceptsDir(File dir) { ret isSameFile(conceptsDir(concepts), dir); } synchronized FileWatchService fileWatcher() { ret fileWatcher if null = new FileWatchService; } synchronized selfType onProjectFileChanged(IVF1 listener) { super.onProjectFileChanged(listener); if (!projectFileListenerInitiated) { set projectFileListenerInitiated; fileWatcher().addRecursiveListener(dbDir(), l1 projectFileChanged); } this; } simplyCached G22ProjectInfo projectInfo() { ret optimizedUniq(concepts, G22ProjectInfo); } RunnablesReferenceQueue runnablesReferenceQueue() { ret masterStuff.runnablesReferenceQueue(); } EphemeralObjectIDs ephemeralObjectIDs() { ret masterStuff.ephemeralObjectIDs(); } // get a remember ephemeral object by ID O eph(long id) { ret ephemeralObjectIDs().get(id); } void openInBrowser(S url) { if (Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) main openInBrowser(url); else { S cmd; if (projectInfo().useFirefox() && isOnPATH("firefox")) cmd = "firefox"; else { cmd = chromeCmd(); if (isRoot()) cmd += " -no-sandbox"; } cmd += " " + platformQuote(url); nohup(cmd); } } S compilationDate() { ret or2(compilationDateFromClassPath(this), "unknown"); } // Global ID for project S projectID() { ret projectInfo().projectID(); } }