Skip to content

Commit

Permalink
Implement basic REPL
Browse files Browse the repository at this point in the history
  • Loading branch information
tferr committed Jan 20, 2025
1 parent 4aed546 commit c781b3b
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 8 deletions.
119 changes: 119 additions & 0 deletions src/main/java/sc/fiji/snt/gui/SNTREPL.java
Original file line number Diff line number Diff line change
@@ -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
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #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 ("<none>"==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
}
""";
}
}
28 changes: 20 additions & 8 deletions src/main/java/sc/fiji/snt/gui/ScriptInstaller.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit c781b3b

Please sign in to comment.