Skip to content

Commit d8df6db

Browse files
committed
optionally display stack trace for an error thrown in a script
1 parent 6c1c0b8 commit d8df6db

File tree

2 files changed

+88
-32
lines changed

2 files changed

+88
-32
lines changed

src/main/java/org/openstreetmap/josm/plugins/scripting/ui/ScriptErrorViewer.java

Lines changed: 79 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33

44
import org.mozilla.javascript.EcmaError;
5+
import org.openstreetmap.josm.data.Preferences;
56
import org.openstreetmap.josm.plugins.scripting.graalvm.GraalVMFacadeFactory;
67

78
import javax.script.ScriptException;
@@ -18,14 +19,28 @@
1819
import java.util.Objects;
1920
import java.util.stream.Collectors;
2021

22+
import static org.openstreetmap.josm.tools.I18n.tr;
23+
2124
/**
2225
* A {@link JPanel} which displays an error thrown during the
2326
* execution of a script.
2427
*/
2528
public class ScriptErrorViewer extends JPanel {
29+
static private final String PREF_KEY_SHOW_STACKTRACE = ScriptErrorViewer.class.getName() + ".show-stack-trace-enabled";
30+
31+
private boolean loadFromPrefShowStackTraceEnabled() {
32+
final var prefs = Preferences.main();
33+
return prefs.getBoolean(PREF_KEY_SHOW_STACKTRACE);
34+
}
35+
36+
private void saveToPrefShowStackTraceEnabled(boolean value) {
37+
final var prefs = Preferences.main();
38+
prefs.putBoolean(PREF_KEY_SHOW_STACKTRACE, value);
39+
}
2640

2741
private JTextPane paneOutput;
2842
private final ScriptErrorViewerModel model;
43+
private boolean showStackTrace = false;
2944

3045
/**
3146
* Creates a new viewer with a new view model.
@@ -57,43 +72,57 @@ public ScriptErrorViewer(@NotNull final ScriptErrorViewerModel model) {
5772
return model;
5873
}
5974

60-
protected void build() {
61-
setLayout(new BorderLayout());
75+
protected JPanel buildOptionsPanel() {
76+
final var p = new JPanel();
77+
p.setLayout(new FlowLayout(FlowLayout.LEFT));
78+
final var cb = new JCheckBox();
79+
p.add(cb);
80+
showStackTrace = loadFromPrefShowStackTraceEnabled();
81+
cb.setSelected(showStackTrace);
82+
cb.addChangeListener(event -> {
83+
showStackTrace = cb.isSelected();
84+
saveToPrefShowStackTraceEnabled(showStackTrace);
85+
refreshView();
86+
});
87+
p.add(new JLabel(tr("Show stack trace")));
88+
return p;
89+
}
90+
91+
protected JComponent buildViewerPanel() {
6292
paneOutput = new JTextPane();
6393
paneOutput.setEditable(false);
64-
JScrollPane editorScrollPane = new JScrollPane(paneOutput);
94+
final var editorScrollPane = new JScrollPane(paneOutput);
6595
editorScrollPane.setVerticalScrollBarPolicy(
6696
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
6797
editorScrollPane.setHorizontalScrollBarPolicy(
6898
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
6999
add(editorScrollPane, BorderLayout.CENTER);
70100
model.addPropertyChangeListener(new ErrorModelChangeListener());
101+
return editorScrollPane;
71102
}
72103

73-
protected void displayPolyglotException(Throwable exception) {
74-
paneOutput.setText(formatPolyglotException(exception));
75-
paneOutput.setCaretPosition(0);
104+
protected void build() {
105+
setLayout(new BorderLayout());
106+
add(buildOptionsPanel(), BorderLayout.NORTH);
107+
add(buildViewerPanel(), BorderLayout.CENTER);
76108
}
77109

78-
protected void displayMozillaEcmaError(EcmaError exception) {
79-
paneOutput.setText(exception.getMessage());
80-
paneOutput.setCaretPosition(0);
110+
protected String formatMozillaEcmaError(EcmaError exception) {
111+
return exception.getMessage();
81112
}
82113

83-
protected void displayScriptException(ScriptException exception) {
84-
paneOutput.setText(exception.getMessage());
85-
paneOutput.setCaretPosition(0);
114+
protected String formatScriptException(ScriptException exception) {
115+
return exception.getMessage();
86116
}
87117

88-
protected void displayGeneralException(Throwable exception) {
118+
protected String formatGeneralException(Throwable exception) {
89119
final var builder = new StringBuilder();
90120
builder.append(exception.getMessage());
91121
builder.append("\n");
92122
final var writer = new StringWriter();
93123
exception.printStackTrace(new PrintWriter(writer));
94124
builder.append(writer.getBuffer());
95-
paneOutput.setText(builder.toString());
96-
paneOutput.setCaretPosition(0);
125+
return builder.toString();
97126
}
98127

99128
/**
@@ -108,36 +137,54 @@ public void displayException(@Null Throwable exception) {
108137
paneOutput.setCaretPosition(0);
109138
return;
110139
}
111-
if (GraalVMFacadeFactory.isGraalVMPresent()) {
140+
var builder = new StringBuilder();
141+
var mozillaEcmaError =
142+
lookupCauseByExceptionType(exception, EcmaError.class);
143+
var scriptException =
144+
lookupCauseByExceptionType(exception, ScriptException.class);
145+
146+
if (mozillaEcmaError != null) {
147+
builder.append(formatMozillaEcmaError((EcmaError) mozillaEcmaError));
148+
} else if (scriptException != null) {
149+
builder.append(formatScriptException((ScriptException) scriptException));
150+
} else if (GraalVMFacadeFactory.isGraalVMPresent()) {
112151
try {
113152
// dynamic lookup necessary
114-
final var clazz = Class.forName("org.graalvm.polyglot.PolyglotException");
115-
final var polyglotException = lookupCauseByExceptionType(exception, clazz);
153+
var clazz = Class.forName("org.graalvm.polyglot.PolyglotException");
154+
var polyglotException = lookupCauseByExceptionType(exception, clazz);
116155
if (polyglotException != null) {
117-
displayPolyglotException(polyglotException);
118-
return;
156+
builder.append(formatPolyglotException(polyglotException));
119157
}
120-
121158
} catch(ClassNotFoundException e) {
122-
return;
159+
// ignore
123160
}
161+
} else {
162+
builder.append(formatGeneralException(exception));
124163
}
125-
final var mozillaEcmaError = lookupCauseByExceptionType(exception, EcmaError.class);
126-
if (mozillaEcmaError != null) {
127-
displayMozillaEcmaError((EcmaError) mozillaEcmaError);
128-
return;
129-
}
130-
final var scriptException = lookupCauseByExceptionType(exception, ScriptException.class);
131-
if (scriptException != null) {
132-
displayScriptException((ScriptException) scriptException);
133-
return;
164+
165+
if (showStackTrace) {
166+
builder
167+
.append("\n")
168+
.append("--------------------------------------------------------")
169+
.append("\n");
170+
var sb = new StringWriter();
171+
var writer = new PrintWriter(sb);
172+
exception.printStackTrace(writer);
173+
builder.append(sb);
134174
}
135-
displayGeneralException(exception);
175+
paneOutput.setText(builder.toString());
176+
paneOutput.setCaretPosition(0);
177+
}
178+
179+
private void refreshView() {
180+
final var exception = model.getError();
181+
displayException(exception);
136182
}
137183

138184
protected @Null Throwable lookupCauseByExceptionType(Throwable t, Class<?> clazz) {
139185
while(t != null) {
140186
if (clazz.isInstance(t)) {
187+
// if (clazz.getName().equals(t.getClass().getName())) {
141188
break;
142189
}
143190
t = t.getCause();

src/main/java/org/openstreetmap/josm/plugins/scripting/ui/ScriptErrorViewerModel.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,13 @@ public void setError(@Null Throwable error) {
7878
public void clearError() {
7979
setError(null);
8080
}
81+
82+
/**
83+
* Replies the currently set error or null
84+
*
85+
* @return the error
86+
*/
87+
public @Null Throwable getError() {
88+
return error;
89+
}
8190
}

0 commit comments

Comments
 (0)