Skip to content

Commit eadbac9

Browse files
committed
Add Source Search Action for SciJava Scripts
1 parent 5fdd0be commit eadbac9

File tree

3 files changed

+211
-0
lines changed

3 files changed

+211
-0
lines changed

pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@
155155
<groupId>org.scijava</groupId>
156156
<artifactId>scijava-common</artifactId>
157157
</dependency>
158+
<dependency>
159+
<groupId>org.scijava</groupId>
160+
<artifactId>scijava-search</artifactId>
161+
</dependency>
158162
<dependency>
159163
<groupId>org.scijava</groupId>
160164
<artifactId>scripting-java</artifactId>
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* #%L
3+
* Script Editor and Interpreter for SciJava script languages.
4+
* %%
5+
* Copyright (C) 2009 - 2022 SciJava developers.
6+
* %%
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice,
11+
* this list of conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26+
* POSSIBILITY OF SUCH DAMAGE.
27+
* #L%
28+
*/
29+
30+
package org.scijava.ui.swing.script.search;
31+
32+
import org.scijava.Context;
33+
import org.scijava.log.LogService;
34+
import org.scijava.module.ModuleInfo;
35+
import org.scijava.plugin.Parameter;
36+
import org.scijava.plugin.Plugin;
37+
import org.scijava.script.ScriptInfo;
38+
import org.scijava.script.ScriptService;
39+
import org.scijava.search.DefaultSearchAction;
40+
import org.scijava.search.SearchAction;
41+
import org.scijava.search.SearchActionFactory;
42+
import org.scijava.search.SearchResult;
43+
import org.scijava.search.module.ModuleSearchResult;
44+
import org.scijava.ui.swing.script.TextEditor;
45+
46+
import java.io.BufferedReader;
47+
import java.io.File;
48+
import java.io.IOException;
49+
import java.net.URISyntaxException;
50+
import java.net.URL;
51+
52+
/**
53+
* Search action for viewing the source code of a SciJava module.
54+
*
55+
* @author Curtis Rueden
56+
*/
57+
@Plugin(type = SearchActionFactory.class)
58+
public class ScriptSourceSearchActionFactory implements SearchActionFactory {
59+
60+
@Parameter private Context context;
61+
62+
@Parameter private LogService log;
63+
@Parameter private ScriptService scriptService;
64+
65+
@Override public boolean supports(final SearchResult result) {
66+
if (!(result instanceof ModuleSearchResult)) return false;
67+
final ModuleInfo info = ((ModuleSearchResult) result).info();
68+
return info instanceof ScriptInfo;
69+
}
70+
71+
@Override public SearchAction create(final SearchResult result) {
72+
ModuleInfo info = ((ModuleSearchResult) result).info();
73+
return new DefaultSearchAction("Source", //
74+
() -> openScriptInTextEditor((ScriptInfo) info));
75+
}
76+
77+
private void openScriptInTextEditor(final ScriptInfo script) {
78+
final TextEditor editor = new TextEditor(context);
79+
80+
final File scriptFile = getScriptFile(script);
81+
if (scriptFile.exists()) {
82+
// script is a file on disk; open it
83+
editor.open(scriptFile);
84+
editor.setVisible(true);
85+
return;
86+
}
87+
88+
// try to read the script from its associated reader
89+
final StringBuilder sb = new StringBuilder();
90+
try (final BufferedReader reader = script.getReader()) {
91+
if (reader != null) {
92+
// script is text from somewhere (a URL?); read it
93+
while (true) {
94+
final String line = reader.readLine();
95+
if (line == null) break; // eof
96+
sb.append(line);
97+
sb.append("\n");
98+
}
99+
}
100+
}
101+
catch (final IOException exc) {
102+
log.error("Error reading script: " + script.getPath(), exc);
103+
}
104+
105+
if (sb.length() > 0) {
106+
// script came from somewhere, but not from a regular file
107+
editor.getEditorPane().setFileName(scriptFile);
108+
editor.getEditorPane().setText(sb.toString());
109+
}
110+
else {
111+
// give up, and report the problem
112+
final String error = "[Cannot load script: " + script.getPath() + "]";
113+
editor.getEditorPane().setText(error);
114+
}
115+
116+
editor.setVisible(true);
117+
}
118+
119+
private File getScriptFile(final ScriptInfo script) {
120+
final URL scriptURL = script.getURL();
121+
try {
122+
if (scriptURL != null) return new File(scriptURL.toURI());
123+
}
124+
catch (final URISyntaxException | IllegalArgumentException exc) {
125+
log.debug(exc);
126+
}
127+
final File scriptDir = scriptService.getScriptDirectories().get(0);
128+
return new File(scriptDir.getPath() + File.separator + script.getPath());
129+
}
130+
131+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* #%L
3+
* Script Editor and Interpreter for SciJava script languages.
4+
* %%
5+
* Copyright (C) 2009 - 2022 SciJava developers.
6+
* %%
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice,
11+
* this list of conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26+
* POSSIBILITY OF SUCH DAMAGE.
27+
* #L%
28+
*/
29+
30+
package org.scijava.script.search;
31+
32+
import org.junit.After;
33+
import org.junit.Before;
34+
import org.junit.Test;
35+
import org.scijava.Context;
36+
import org.scijava.script.ScriptInfo;
37+
import org.scijava.search.SearchActionFactory;
38+
import org.scijava.search.SearchResult;
39+
import org.scijava.search.module.ModuleSearchResult;
40+
import org.scijava.ui.swing.script.search.ScriptSourceSearchActionFactory;
41+
42+
import java.io.StringReader;
43+
44+
import static org.junit.Assert.assertTrue;
45+
46+
/**
47+
* Basic regression test for {@link ScriptSourceSearchActionFactory}
48+
*
49+
* @author Gabriel Selzer
50+
*/
51+
public class ScriptSourceSearchActionFactoryTest {
52+
53+
private Context context;
54+
private final SearchActionFactory factory =
55+
new ScriptSourceSearchActionFactory();
56+
57+
// -- Test setup --
58+
59+
@Before public void setUp() {
60+
context = new Context();
61+
}
62+
63+
@After public void tearDown() {
64+
context.dispose();
65+
}
66+
67+
@Test public void testScriptSourceAction()
68+
{
69+
final String script = "\"Hello World!\"\n";
70+
final StringReader reader = new StringReader(script);
71+
final ScriptInfo info = new ScriptInfo(context, "test.groovy", reader);
72+
final SearchResult searchResult = new ModuleSearchResult(info, "");
73+
assertTrue(factory.supports(searchResult));
74+
}
75+
76+
}

0 commit comments

Comments
 (0)