diff --git a/src/main/java/sc/fiji/snt/gui/SNTREPL.java b/src/main/java/sc/fiji/snt/gui/SNTREPL.java new file mode 100644 index 00000000..60288fc6 --- /dev/null +++ b/src/main/java/sc/fiji/snt/gui/SNTREPL.java @@ -0,0 +1,119 @@ +/*- + * #%L + * Fiji distribution of ImageJ for the life sciences. + * %% + * Copyright (C) 2010 - 2025 Fiji developers. + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +package sc.fiji.snt.gui; + +import org.scijava.Context; +import org.scijava.ui.swing.script.InterpreterWindow; +import sc.fiji.snt.SNTUtils; + +import javax.script.ScriptException; +import java.awt.*; + +/** + * SNT's (basic) Groovy REPL. + * + * @author Tiago Ferreira + */ +public class SNTREPL extends InterpreterWindow { + + public SNTREPL(final Context context) { + super(context, ".groovy"); + init(); + setTitle("SNT Scripting REPL"); + final FontMetrics fm = getContentPane().getFontMetrics(getContentPane().getFont()); + final int w = fm.stringWidth("type a statement to evaluate it with the active language."); + final int h = fm.getHeight() * 20; + setMinimumSize(new Dimension(w * 2, h)); + pack(); + } + + private void init() { + try { + getInterpreter().eval(apiFunction()); + getInterpreter().eval(initCmds()); + print("SNT REPL: The following variables/functions have been loaded:"); + print(" instance | sc.fiji.snt.SNT"); + print(" pafm | sc.fiji.snt.PathAndFillManager"); + print(" ui | sc.fiji.snt.SNTUI"); + print(" snt | sc.fiji.snt.SNTService"); // loaded by scijava + print(" api(obj, <'keyword'>) | inspects the API of an object"); + print(""); + } catch (final ScriptException ex) { + SNTUtils.error("initialization failed", ex); + } + } + + private String initCmds() { + return """ + instance = snt.getInstance() + pafm = snt.getPathAndFillManager() + ui = snt.getUI() + """; + } + + private String apiFunction() { + return """ + def api(obj, keyword="") { + if (obj == null) { println("api: obj is null"); return } + def list = obj.class.declaredMethods.findAll { !it.name.contains("\\$") } + if ("" != keyword) list = list.findAll{ it.name.toLowerCase().contains(keyword) } + println("${list.size()} method(s) available in ${obj.class.getName()}:") + list.sort{ it.name }.each { + def params = it.parameters.collect { it.toString().split("\\\\.").last() } + def name = it.name + "(" + params.join(", ") + ")" + def returnType = it.returnType.toString().split("\\s|\\\\.").last() + println(" ${name.padRight(45)} -> ${returnType}") + } + return "" + } + """; + } + + @SuppressWarnings("unused") + private String apiFunctionNotebook() { + return """ + def void api(obj, keyword="") { + def list = notebook.methods(obj) + list = list.findAll { it["name"].toLowerCase().contains(keyword) } + println("${obj.class.getName()} methods:") + list.forEach( m -> { + def name = m["name"] + def arg = prettify(m["arguments"].replace("java.lang.", "")) + def res = prettify(m["returns"]) + println(" $name($arg) ${""==res?"":"-> $res"}") + }) + println() + } + def prettify(arg) { + if (""==arg || "void"==arg ) return "" + if (arg.contains(";") || arg.contains("[") ) { + arg = arg.replace("L", "").replace(";", "") + if (arg.contains("[")) arg = arg.replace("[", "") + "[]" + arg = arg.replaceAll("\\\\bI\\\\b", "int") + arg = arg.replaceAll("\\\\bD\\\\b", "double") + } + return arg + } + """; + } +} diff --git a/src/main/java/sc/fiji/snt/gui/ScriptInstaller.java b/src/main/java/sc/fiji/snt/gui/ScriptInstaller.java index e804c8f2..d982402e 100644 --- a/src/main/java/sc/fiji/snt/gui/ScriptInstaller.java +++ b/src/main/java/sc/fiji/snt/gui/ScriptInstaller.java @@ -334,22 +334,34 @@ public JMenu getScriptsMenu(final Pattern excludePattern, final String... direct nMenu.setIcon(IconFactory.getMenuIcon(GLYPH.PLUS)); nMenu.add(mi1); nMenu.add(mi2); + + final JMenuItem mi3 = new JMenuItem("REPL", IconFactory.getMenuIcon(GLYPH.CODE)); + mi3.addActionListener(e -> { + final SNTREPL repl = new SNTREPL(SNTUtils.getContext()); + repl.setLocationRelativeTo(ui); + SwingUtilities.invokeLater(() -> repl.setVisible(true)); + }); + nMenu.addSeparator(); + nMenu.add(mi3); + + sMenu.add(listMenu); + sMenu.addSeparator(); + sMenu.add(nMenu); + sMenu.add(reloadMI); + if (ui != null) { - final JMenuItem mi3 = new JMenuItem("Record... (Experimental)", IconFactory.getMenuIcon(GLYPH.CIRCLE)); - mi3.addActionListener(e -> { + final JMenuItem mi4 = new JMenuItem("Record... (Experimental)", IconFactory.getMenuIcon(GLYPH.CIRCLE)); + mi4.addActionListener(e -> { if (ui.getRecorder(false) == null) { ui.getRecorder(true).setVisible(true); } else { ui.error("Script Recorder is already open."); } }); - nMenu.addSeparator(); - nMenu.add(mi3); + sMenu.addSeparator(); + sMenu.add(mi4); } - sMenu.add(listMenu); - sMenu.addSeparator(); - sMenu.add(nMenu); - sMenu.add(reloadMI); + sMenu.addSeparator(); sMenu.add(about()); return sMenu;