sclass JLeftArrowScriptIDE > MetaWithChangeListeners is Swingable { settable IVarWithNotify lvScript = stringLiveValue(); settable S sectionTitle = "Left arrow script"; settable bool withResultPanel = true; // how long to wait before compiling after text is changed (seconds) settable double compileDelay = 0.1; sS helpText = !include string #1034045; transient settableWithVar LASCompileResult compileResult; transient volatile RSyntaxTextAreaWithSearch taScript; transient new RSTADummyParser dummyParser; // for error highlighting transient ReliableSingleThread rstCompile = new(l0 compile); transient gettable JPanel buttons = jline(); transient JButton btnRun; transient CollapsibleLeftPanel collapsibleResultPanel; transient G22ScriptResultPanel resultPanel; transient JPopDownButton popDownButton; transient LeftArrowCompletionProvider completionProvider; settable transient G22Utils g22utils; settable double scriptTimeout = 10.0; settable transient bool showTitle = true; // set by client settable transient O sourceInfo; transient Runnable rRecompileIfError = l0 recompileIfError; transient swappable GazelleV_LeftArrowScriptParser makeParser() { ret g22utils.leftArrowParser().sourceInfo(sourceInfo); } interface GoToDefinitionHandler { Runnable get(TokPtr tokPtr); } transient gettable L goToDefinitionHandlers = syncL(); class LeftArrowCompletionProvider extends DefaultCompletionProvider { @Override public L getCompletionsImpl(JTextComponent comp) { try { S text = main getText(comp); GazelleV_LeftArrowScriptParser parser = makeParser(); LeftArrowScriptAutoCompleter completer = new(g22utils, parser); completer.onAdaptingSearcher(-> g22utils.addingAdditionalAutoCompletes(completer)); //enableScaffolding(completer); completer.seek(text, getCaretPosition(comp)); ret map(completer.searcher().withScores(), completion -> { BasicCompletion c = new(this, completion!); c.setRelevance((int) completion.score()); ret c; }); } catch print e { ret ll(); } } } void goToPosition_noFocus(LineAndColumn lineAndCol) { if (lineAndCol == null) ret; try { moveCaretAndScroll(textArea(), lineAndCol); } catch e { print("Trying again: " + e); awtLater(1.0, -> { moveCaretAndScroll(textArea(), lineAndCol); }); } } void goToPosition(LineAndColumn lineAndCol) { focus(textArea()); goToPosition_noFocus(lineAndCol); } JComponent wrapStatusLabel(JComponent lbl) { onLeftClick(lbl, -> goToPosition(compileResult?.errorLineAndCol())); popDownButton = swing(-> new JPopDownButton("Help")); popDownButton.onFillingMenu(menu -> addMenuItems(menu, "Show Scripting Help", rThread { showTextWordWrapped("Gazelle 'Left arrow script' Help", helpText) }, "Show Global Class Names", rThread showGlobalClassNames, "Convert to Java", rThread convertToJava, )); ret centerAndEastWithMargin( jBorderlessHigherScrollPane(lbl), jfullcenter(buttons)); } cachedVisual swing(-> { taScript = g22utils.newSyntaxTextArea(l1 wrapStatusLabel); bindToComponent(textArea(), -> g22utils.masterStuff().onNewClassesDefined(rRecompileIfError), -> g22utils.masterStuff().removeNewClassesDefinedListener(rRecompileIfError)); bindTextComponentToVarWithNotify_noInitialUndo(textArea(), lvScript); dummyParser.install(textArea()); //onCtrlEnter(textArea(), rThread runScript); // F5 to run! addKeyListener(textArea(), functionKeyListener(5, rThread runScript); // Ctrl+B to go to definition addKeyListener(textArea(), ctrlLetterKeyListener('b', rThread goToDefinition); // Permanent auto-compile on any text input awtCalcEvery(textArea(), compileDelay, rstCompile); installCompletionProvider(completionProvider = new LeftArrowCompletionProvider, textArea()); JComponent vis = taScript.visualize(); if (showTitle) vis = jCenteredSection(sectionTitle, vis); vis = wrapSection(vis); addAll(buttons, btnRun = toolTip("Run script (F5)", jbutton("Run" := rThread runScript)), popDownButton); if (withResultPanel) { resultPanel = new G22ScriptResultPanel; collapsibleResultPanel = new CollapsibleLeftPanel(false, "Output", resultPanel.visualize(), vis); collapsibleResultPanel.sidePanelMargins = c -> withTopAndLeftMargin(c); ret collapsibleResultPanel.visualize(); } else ret vis; }); swappable JComponent wrapSection(JComponent c) { ret c; } RSyntaxTextArea textArea() { if (taScript == null) visualize(); ret taScript.textArea(); } void setText(S text) { main setText(textArea(), text); } private void compile { var script = lvScript!; var result = compileResult; if (!g22utils().compileResultValid(result, script)) { result = newCompileResult(); result.script = script; result.makeParser = l0 makeParser; result.compile(); compileResult(result); showStatus(str(compileResult)); updateRunButtonState(); // send errors to highlighter L errors = new L; if (result.compileError != null) { LineAndColumn lineAndCol = result.errorLineAndCol(); if (lineAndCol != null) errors.add(new RSTADummyParser.Error() .msg(result.errorToString()) .start(lineAndCol) .end(LineAndColumn(lineAndCol.line+1, 1))); } dummyParser.setErrors(result.script, errors, textArea()); } } void updateRunButtonState() { setEnabled(btnRun, runButtonShouldBeEnabled()); } swappable bool runButtonShouldBeEnabled() { ret compileResult != null && compileResult.runnable(); } LASCompileResult freshCompileResult() { rstCompile.triggerAndWait(); ret compileResult; } GazelleV_LeftArrowScript.Script parsedScript() { ret freshCompileResult().parsedScript; } swappable void runScript() { var result = freshCompileResult(); if (result.parsedScript != null) { var value = runResultWithTimestamps(-> callCompiledObjectWithTimeout(result.parsedScript)); showScriptResult(value); } } void showScriptResult(OKOrError result) { if (result cast RunResultWithTimestamps) resultPanel?.logView.setText(str(result.printOutput())); if (result.isOK()) { setStatus(shorten(g22utils.stringify(result!))); var objVisualizer = makeObjectVisualizer(result!); if (result cast RunResultWithTimestamps) { var duration = result.duration(); //print(+duration); if (duration != null) { long nanos = result.duration().toNanos(); //printVars(+nanos, +objVisualizer); objVisualizer.nanos(nanos); } } if (collapsibleResultPanel != null) objVisualizer.withTypeAndTime(false); resultPanel?.scpResult.set(objVisualizer); if (collapsibleResultPanel != null) collapsibleResultPanel.sidePanelName("Output" + appendBracketed(objVisualizer.objectInfos())); } else { setStatus( //exceptionToStringShorter_dontDropOuterExceptions exceptionToStringShorter (result.error())); resultPanel?.scpResult.set(jErrorView(result.getError())); } collapsibleResultPanel?.expand(); } /* compile result used to include result of execution class CompileResult > LASCompileResult { OKOrError result; }*/ void setStatus aka showStatus(S status) { taScript?.setStatus(" " + unnull(status)); } void showRuntimeError(Throwable e) { showStatus(exceptionToStringShorter(e)); } swappable VarContext makeVarContextForExecution() { ret new FlexibleVarContext; } O callCompiledObjectWithTimeout(double timeoutSeconds default scriptTimeout, GazelleV_LeftArrowScript.Script script, VarContext ctx default makeVarContextForExecution()) { ret g22utils.evalRegisteredCode(timeoutSeconds, str(script), -> script.get(ctx)); } /*GazelleV_LeftArrowScriptParser makeParser2() { var parser = makeParser(); print("Function containers: " + parser.functionContainers); ret parser; }*/ void showGlobalClassNames() { showText("Global Class Names", pnlToString(toCIMap(makeParser().globalClassNames()))); } // only after visualize void setEditable(bool b) { main setEditable(textArea(), b); } swappable LASCompileResult newCompileResult() { ret new LASCompileResult; } void convertToJava { pcall-infobox { new ConvertLASToJava converter; //enableScaffolding(converter); showText("Java conversion - " + sectionTitle(), strOrNull(converter.get(parsedScript(), true))); } } void goToDefinition { S text, int iChar = unpair textAndCaretPosition(textArea()); LS tok = lasTok(text); int iTok = charToTokenIndex_left(tok, iChar); TokPtr tokPtr = new(tok, iTok); var action = goToDefinitionAction(tokPtr); if (action != null) pcallF(action); else flatInfoBox("No definition found"); } Runnable goToDefinitionAction(TokPtr tokPtr) { for (handler : cloneList(goToDefinitionHandlers())) try object handler.get(tokPtr); LS tok = tokPtr.list(); int iTok = tokPtr.idx(); S id = lastIdentifier(subList(tok, iTok-2, iTok+1)); //printVars("goToDefinition", +iTok, token := quote(token)); if (id != null) { S name = lookupStandardFunctionOrClassNameIC(id); if (name != null) { S snippetID = sfOrSCSnippet(id); if (snippetID != null) { // Should always be true ret -> { infoBox("Opening " + quote(name)); g22utils.openInBrowser(snippetURL(snippetID)); }; } } } null; } void recompile { compileResult = null; rstCompile.trigger(); } void recompileIfError { var result = compileResult; //print("JLeftArrowScriptIDE.recompileIfError " + result); if (result != null && result.hasError()) recompile(); } swappable G22JavaObjectVisualizer makeObjectVisualizer(O result) { ret G22JavaObjectVisualizer(g22utils, result) .allowDescendingIntoListElements(true); } void addGoToDefinitionHandler(GoToDefinitionHandler handler) { goToDefinitionHandlers.add(handler); } bool visible aka isShowing() { var ta = taScript; ret ta != null && main isShowing(ta.textArea); } S getText() { var ta = taScript; if (ta == null) null; ret main getText(ta.textArea); } }