Skip to content

Commit a571896

Browse files
committed
Merge pull request #127 from scijava/interpreter
Add the user-interface independent part of a generic script interpreter
2 parents d0c26b5 + f9c3057 commit a571896

File tree

10 files changed

+928
-3
lines changed

10 files changed

+928
-3
lines changed

src/main/java/org/scijava/prefs/DefaultPrefService.java

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,28 @@ public List<String> getList(final Class<?> prefClass) {
378378
return getList(preferences);
379379
}
380380

381+
@Override
382+
public Iterable<String> getIterable(final String key) {
383+
return getIterable((Class<?>) null, key);
384+
}
385+
386+
@Override
387+
public Iterable<String> getIterable(final Class<?> prefClass, final String key) {
388+
final Preferences preferences = prefs(prefClass);
389+
return getIterable(preferences.node(key));
390+
}
391+
392+
@Override
393+
public void putIterable(final Iterable<String> iterable, final String key) {
394+
putIterable((Class<?>) null, iterable, key);
395+
}
396+
397+
@Override
398+
public void putIterable(final Class<?> prefClass, final Iterable<String> iterable, final String key) {
399+
final Preferences preferences = prefs(prefClass);
400+
putIterable(preferences.node(key), iterable);
401+
}
402+
381403
// -- Helper methods --
382404

383405
private void clear(final Preferences preferences, final String key) {
@@ -460,6 +482,60 @@ private List<String> getList(final Preferences preferences) {
460482
return list;
461483
}
462484

485+
private void putIterable(final Preferences preferences,
486+
final Iterable<String> iterable)
487+
{
488+
if (preferences == null) {
489+
throw new IllegalArgumentException("Preferences not set.");
490+
}
491+
int index = 0;
492+
for (final String value : iterable) {
493+
preferences.put("" + index++, value == null ? null : value.toString());
494+
}
495+
}
496+
497+
private Iterable<String> getIterable(final Preferences preferences)
498+
{
499+
if (preferences == null) {
500+
throw new IllegalArgumentException("Preferences not set.");
501+
}
502+
return new Iterable<String>() {
503+
@Override
504+
public Iterator<String> iterator() {
505+
return new Iterator<String>() {
506+
private String value;
507+
private int index;
508+
{
509+
findNext();
510+
}
511+
512+
@Override
513+
public String next() {
514+
final String result = value;
515+
findNext();
516+
return result;
517+
}
518+
519+
@Override
520+
public boolean hasNext() {
521+
return value != null;
522+
}
523+
524+
@Override
525+
public void remove() {
526+
throw new UnsupportedOperationException();
527+
}
528+
529+
private void findNext() {
530+
if (index < 0) return;
531+
value = preferences.get("" + index, null);
532+
index = value == null ? -1 : index + 1;
533+
}
534+
};
535+
}
536+
};
537+
}
538+
463539
private Preferences prefs(final Class<?> c) {
464540
return Preferences.userNodeForPackage(c == null ? PrefService.class : c);
465541
}

src/main/java/org/scijava/prefs/PrefService.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,4 +194,24 @@ public interface PrefService extends SciJavaService {
194194
* prefs.
195195
*/
196196
List<String> getList(Class<?> prefClass);
197+
198+
/**
199+
* Puts an iterable into the preferences.
200+
*/
201+
void putIterable(Iterable<String> iterable, String key);
202+
203+
/**
204+
* Puts an iterable into the preferences.
205+
*/
206+
void putIterable(Class<?> prefClass, Iterable<String> iterable, String key);
207+
208+
/**
209+
* Gets an iterable from the preferences.
210+
*/
211+
Iterable<String> getIterable(String key);
212+
213+
/**
214+
* Gets an iterable from the preferences.
215+
*/
216+
Iterable<String> getIterable(Class<?> prefClass, String key);
197217
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2014 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
package org.scijava.script;
32+
33+
import javax.script.ScriptEngine;
34+
import javax.script.ScriptException;
35+
36+
import org.scijava.prefs.PrefService;
37+
38+
/**
39+
* The default implementation of a {@link ScriptInterpreter}.
40+
*
41+
* @author Johannes Schindelin
42+
*/
43+
public class DefaultScriptInterpreter implements ScriptInterpreter {
44+
45+
private final ScriptLanguage language;
46+
private final ScriptEngine engine;
47+
private final History history;
48+
49+
/**
50+
* Constructs a new {@link DefaultScriptInterpreter}.
51+
*
52+
* @param scriptService the script service
53+
* @param language the script language
54+
*/
55+
public DefaultScriptInterpreter(final PrefService prefs,
56+
final ScriptService scriptService, final ScriptLanguage language)
57+
{
58+
this.language = language;
59+
engine = language.getScriptEngine();
60+
history = new History(prefs, engine.getClass().getName());
61+
readHistory();
62+
}
63+
64+
@Override
65+
public synchronized void readHistory() {
66+
if (history == null) return;
67+
history.read();
68+
}
69+
70+
@Override
71+
public synchronized void writeHistory() {
72+
if (history == null) return;
73+
history.write();
74+
}
75+
76+
@Override
77+
public synchronized String walkHistory(final String currentCommand,
78+
final boolean forward)
79+
{
80+
if (history == null) return currentCommand;
81+
history.replace(currentCommand);
82+
return forward ? history.next() : history.previous();
83+
}
84+
85+
@Override
86+
public void eval(final String command) throws ScriptException {
87+
if (history != null) history.add(command);
88+
if (engine == null) throw new java.lang.IllegalArgumentException();
89+
engine.eval(command);
90+
}
91+
92+
@Override
93+
public ScriptLanguage getLanguage() {
94+
return language;
95+
}
96+
97+
@Override
98+
public ScriptEngine getEngine() {
99+
return engine;
100+
}
101+
102+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2014 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
32+
package org.scijava.script;
33+
34+
import org.scijava.prefs.PrefService;
35+
import org.scijava.util.LastRecentlyUsed;
36+
37+
/**
38+
* Container for a script language's interpreter history.
39+
*
40+
* @author Johannes Schindelin
41+
*/
42+
class History {
43+
44+
protected static final long serialVersionUID = 1L;
45+
46+
private static final String PREFIX = "History.";
47+
private final int MAX_ENTRIES = 1000;
48+
49+
private final PrefService prefs;
50+
private final String name;
51+
private final LastRecentlyUsed<String> entries = new LastRecentlyUsed<String>(MAX_ENTRIES);
52+
private String currentCommand = "";
53+
private int position = -1;
54+
55+
/**
56+
* Constructs a history object for a given scripting language.
57+
*
58+
* @param name the name of the scripting language
59+
*/
60+
public History(final PrefService prefs, final String name) {
61+
this.prefs = prefs;
62+
this.name = name;
63+
}
64+
65+
/**
66+
* Read back a persisted history.
67+
*/
68+
public void read() {
69+
entries.clear();
70+
for (final String item : prefs.getIterable(getClass(), PREFIX + name)) {
71+
entries.addToEnd(item);
72+
};
73+
}
74+
75+
/**
76+
* Persist the history.
77+
*
78+
* @see {@link Prefs}
79+
*/
80+
public void write() {
81+
prefs.putIterable(getClass(), entries, PREFIX + name);
82+
}
83+
84+
/**
85+
* Adds the most recently issued command.
86+
*
87+
* @param command the most recent command to add to the history
88+
*/
89+
public void add(final String command) {
90+
entries.add(command);
91+
position = -1;
92+
currentCommand = "";
93+
}
94+
95+
public boolean replace(final String currentCommand) {
96+
if (position < 0) {
97+
this.currentCommand = currentCommand;
98+
return false;
99+
}
100+
return entries.replace(position, currentCommand);
101+
}
102+
103+
/**
104+
* Navigates to the next (more recent) command.
105+
* <p>
106+
* This method wraps around, i.e. it returns {@code null} when there is no
107+
* more-recent command in the history.
108+
* </p>
109+
*
110+
* @return the next command
111+
*/
112+
public String next() {
113+
position = entries.next(position);
114+
return position < 0 ? currentCommand : entries.get(position);
115+
}
116+
117+
/**
118+
* Navigates to the previous (i.e less recent) command.
119+
* <p>
120+
* This method wraps around, i.e. it returns {@code null} when there is no
121+
* less-recent command in the history.
122+
* </p>
123+
*
124+
* @return the previous command
125+
*/
126+
public String previous() {
127+
position = entries.previous(position);
128+
return position < 0 ? currentCommand : entries.get(position);
129+
}
130+
131+
@Override
132+
public String toString() {
133+
final StringBuilder builder = new StringBuilder();
134+
int position = -1;
135+
for (;;) {
136+
position = entries.previous(position);
137+
if (position < 0) break;
138+
if (builder.length() > 0) builder.append(" -> ");
139+
if (this.position == position) builder.append("[");
140+
builder.append(entries.get(position));
141+
if (this.position == position) builder.append("]");
142+
}
143+
return builder.toString();
144+
}
145+
}

0 commit comments

Comments
 (0)