Skip to content

Commit 8ad318b

Browse files
committed
Add a processor for #@script directives
See #294.
1 parent 8f8e2c3 commit 8ad318b

File tree

1 file changed

+162
-0
lines changed

1 file changed

+162
-0
lines changed
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2017 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck
7+
* Institute of Molecular Cell Biology and Genetics, University of
8+
* Konstanz, and KNIME GmbH.
9+
* %%
10+
* Redistribution and use in source and binary forms, with or without
11+
* modification, are permitted provided that the following conditions are met:
12+
*
13+
* 1. Redistributions of source code must retain the above copyright notice,
14+
* this list of conditions and the following disclaimer.
15+
* 2. Redistributions in binary form must reproduce the above copyright notice,
16+
* this list of conditions and the following disclaimer in the documentation
17+
* and/or other materials provided with the distribution.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
23+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29+
* POSSIBILITY OF SUCH DAMAGE.
30+
* #L%
31+
*/
32+
33+
package org.scijava.script.process;
34+
35+
import java.util.Map;
36+
37+
import org.scijava.MenuPath;
38+
import org.scijava.Priority;
39+
import org.scijava.log.LogService;
40+
import org.scijava.module.ModuleInfo;
41+
import org.scijava.plugin.Parameter;
42+
import org.scijava.plugin.Plugin;
43+
44+
/**
45+
* A {@link ScriptProcessor} which parses the {@code #@script} directive.
46+
* <p>
47+
* The syntax is:
48+
* </p>
49+
*
50+
* <pre>
51+
* #@script(key1=value1, key2=value2, ...)
52+
* </pre>
53+
* <p>
54+
* Supported keys include:
55+
* </p>
56+
* <ul>
57+
* <li>{@code name} - The name of the script.</li>
58+
* <li>{@code label} - The human-readable label to use (e.g., in the menu
59+
* structure).</li>
60+
* <li>{@code description} - A longer description of the script (e.g., for use
61+
* as a tool tip).</li>
62+
* <li>{@code menuPath} - Abbreviated menu path defining where the script is
63+
* shown in the menu structure. Use greater than sign ({@code >}) as a
64+
* separator.</li>
65+
* <li>{@code menuRoot} - String identifier naming the menu to which this script
66+
* belongs.</li>
67+
* <li>{@code iconPath} - Path to the plugin's icon (e.g., shown in the menu
68+
* structure).</li>
69+
* <li>{@code priority} - Priority of the script. Larger values are higher
70+
* priority. Value can be written as a {@code double} constant, or as one of the
71+
* following convenient shorthands: {@code first}, {@code extremely-high},
72+
* {@code very-high}, {@code high}, {@code normal}, {@code low},
73+
* {@code very-low}, {@code extremely-low}, {@code last}.</li>
74+
* <li>{@code headless} - Provides a "hint" as to whether the script would
75+
* behave correctly in a headless context. Do <em>not</em> specify
76+
* {@code headless = true} unless the script refrains from using any UI-specific
77+
* features (e.g., AWT or Swing calls).</li>
78+
* </ul>
79+
* <p>
80+
* Any other key-value pairs encountered are stored as properties via the
81+
* {@link ModuleInfo#set(String, String)} method.
82+
* </p>
83+
* <p>
84+
* See also the @{@link Plugin} annotation, which mostly lines up with this list
85+
* of attributes.
86+
* </p>
87+
* <p>
88+
* Here are a few examples:
89+
* </p>
90+
* <ul>
91+
* <li>{@code #@script(name = "extra-functions")}</li>
92+
* <li>{@code #@script(headless = true)}</li>
93+
* <li>{@code #@script(menuPath = "Image > Import > Text...")}</li>
94+
* </ul>
95+
*
96+
* @author Curtis Rueden
97+
*/
98+
@Plugin(type = ScriptProcessor.class)
99+
public class ScriptDirectiveScriptProcessor extends DirectiveScriptProcessor {
100+
101+
public ScriptDirectiveScriptProcessor() {
102+
super(directive -> "script".equals(directive));
103+
}
104+
105+
@Parameter
106+
private LogService log;
107+
108+
// -- Internal DirectiveScriptProcessor methods --
109+
110+
@Override
111+
protected String process(final String directive,
112+
final Map<String, Object> attrs, final String theRest)
113+
{
114+
for (final String k : attrs.keySet()) {
115+
assignAttribute(k == null ? "name" : k, attrs.get(k));
116+
}
117+
return "";
118+
}
119+
120+
// -- Helper methods --
121+
122+
private <T> void assignAttribute(final String k, final Object v) {
123+
if (is(k, "name")) info().setName(as(v, String.class));
124+
else if (is(k, "label")) info().setLabel(as(v, String.class));
125+
else if (is(k, "description")) info().setDescription(as(v, String.class));
126+
else if (is(k, "menuPath")) {
127+
info().setMenuPath(new MenuPath(as(v, String.class)));
128+
}
129+
else if (is(k, "menuRoot")) info().setMenuRoot(as(v, String.class));
130+
else if (is(k, "iconPath")) info().setIconPath(as(v, String.class));
131+
else if (is(k, "priority")) {
132+
final Double priority = priority(v);
133+
if (priority != null) info().setPriority(priority);
134+
}
135+
else if (is(k, "headless") && as(v, boolean.class)) {
136+
// NB: There is no ModuleInfo#setHeadless(boolean).
137+
// So we add a "headless" property; see ScriptInfo#canRunHeadless().
138+
info().set("headless", "true");
139+
}
140+
else info().set(k, v.toString());
141+
}
142+
143+
private Double priority(final Object p) {
144+
final Double pDouble = as(p, Double.class);
145+
if (pDouble != null) return pDouble;
146+
147+
final String pString = as(p, String.class);
148+
if (pString == null) return null;
149+
150+
final String lString = pString.toLowerCase();
151+
if (lString.matches("first")) return Priority.FIRST;
152+
if (lString.matches("extremely[ _-]?high")) return Priority.EXTREMELY_HIGH;
153+
if (lString.matches("very[ _-]?high")) return Priority.VERY_HIGH;
154+
if (lString.matches("high")) return Priority.HIGH;
155+
if (lString.matches("normal")) return Priority.NORMAL;
156+
if (lString.matches("low")) return Priority.LOW;
157+
if (lString.matches("very[ _-]?low")) return Priority.VERY_LOW;
158+
if (lString.matches("extremely[ _-]?low")) return Priority.EXTREMELY_LOW;
159+
if (lString.matches("last")) return Priority.LAST;
160+
return null;
161+
}
162+
}

0 commit comments

Comments
 (0)