Skip to content

Commit 27c5f20

Browse files
committed
Fixing a couple of minor bugs with the expression evaluator
* need to keep a pointer to the `XDebuggerEvaluator` to prevent it from getting garbage-collected * right after evaluating an expression, the erlang debugger will trigger a new "breakpoint reached" event; unfortunately, that means this plugin will try to concurrently render the new state of the bindings as well as the result from the evaluation, which Intellij doesn't seem to handle too well, resulting in the debugging session losing track of what the current frame is... so to fix that we just ignore the next "breakpoint reached" event right after evaluating an expression... better ideas welcome! Also improving the way responses are handled: parsing errors and uncaught exceptions now appear as errors.
1 parent 004db36 commit 27c5f20

File tree

2 files changed

+40
-7
lines changed

2 files changed

+40
-7
lines changed

src/org/intellij/erlang/debugger/xdebug/ErlangStackFrame.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public class ErlangStackFrame extends XStackFrame {
4141
private final ErlangXDebugProcess myDebugProcess;
4242
private final ErlangTraceElement myTraceElement;
4343
private final ErlangSourcePosition mySourcePosition;
44+
private XDebuggerEvaluator myEvaluator = null;
4445

4546
public ErlangStackFrame(@NotNull ErlangXDebugProcess debugProcess,
4647
@NotNull ErlangTraceElement traceElement) {
@@ -58,14 +59,15 @@ public ErlangStackFrame(@NotNull ErlangXDebugProcess debugProcess,
5859
@Nullable
5960
@Override
6061
public XDebuggerEvaluator getEvaluator() {
61-
return new XDebuggerEvaluator() {
62+
myEvaluator = new XDebuggerEvaluator() {
6263
@Override
6364
public void evaluate(@NotNull String expression,
6465
@NotNull XEvaluationCallback callback,
6566
@Nullable XSourcePosition expressionPosition) {
6667
myDebugProcess.evaluateExpression(expression, callback, myTraceElement);
6768
}
6869
};
70+
return myEvaluator;
6971
}
7072

7173
@Nullable

src/org/intellij/erlang/debugger/xdebug/ErlangXDebugProcess.java

+37-6
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616

1717
package org.intellij.erlang.debugger.xdebug;
1818

19+
import com.ericsson.otp.erlang.OtpErlangAtom;
1920
import com.ericsson.otp.erlang.OtpErlangObject;
2021
import com.ericsson.otp.erlang.OtpErlangPid;
22+
import com.ericsson.otp.erlang.OtpErlangTuple;
2123
import com.intellij.execution.ExecutionException;
2224
import com.intellij.execution.configurations.GeneralCommandLine;
2325
import com.intellij.execution.process.OSProcessHandler;
@@ -72,7 +74,6 @@
7274
import static org.intellij.erlang.debugger.ErlangDebuggerLog.LOG;
7375

7476
public class ErlangXDebugProcess extends XDebugProcess implements ErlangDebuggerEventListener {
75-
private final XDebugSession mySession;
7677
private final ExecutionEnvironment myExecutionEnvironment;
7778
private final ErlangRunningState myRunningState;
7879
private final ErlangDebuggerNode myDebuggerNode;
@@ -83,11 +84,16 @@ public class ErlangXDebugProcess extends XDebugProcess implements ErlangDebugger
8384
private ConcurrentHashMap<ErlangSourcePosition, XLineBreakpoint<ErlangLineBreakpointProperties>> myPositionToLineBreakpointMap =
8485
new ConcurrentHashMap<>();
8586
private XDebuggerEvaluator.XEvaluationCallback myEvalCallback = null;
87+
// right after evaluating an expression, the erlang debugger will trigger a new "breakpoint reached" event
88+
// unfortunately, that means this plugin will try to concurrently render the new state of the bindings as
89+
// well as the result from the evaluation, which Intellij doesn't seem to handle too well, resulting in
90+
// the debugging session losing track of what the current frame is... so we just ignore the next "breakpoint
91+
// reached" event right after evaluating an expression - better ideas welcome!
92+
private boolean ignoreNextBreakpointReachedEvent = false;
8693

8794
public ErlangXDebugProcess(@NotNull XDebugSession session, ExecutionEnvironment env) throws ExecutionException {
8895
//TODO add debug build targets and make sure the project is built using them.
8996
super(session);
90-
mySession = session;
9197

9298
session.setPauseActionSupported(false);
9399

@@ -124,17 +130,36 @@ public ErlangDebugLocationResolver getLocationResolver() {
124130
public synchronized void evaluateExpression(@NotNull String expression,
125131
@NotNull XDebuggerEvaluator.XEvaluationCallback callback,
126132
@NotNull ErlangTraceElement traceElement) {
127-
// need to pause the debugging session otherwise the callback might get invalidated
128-
mySession.pause();
129133
myEvalCallback = callback;
134+
// see the comment about ignoreNextBreakpointReachedEvent
135+
ignoreNextBreakpointReachedEvent = true;
130136
myDebuggerNode.evaluate(expression, traceElement);
131137
}
132138

133139
@Override
134140
public synchronized void handleEvaluationResponse(OtpErlangObject response) {
135141
if (myEvalCallback != null) {
136-
myEvalCallback.evaluated(ErlangXValueFactory.create(response));
137-
mySession.resume();
142+
String error = null;
143+
144+
if (response instanceof OtpErlangAtom && ((OtpErlangAtom) response).atomValue().equals("Parse error")) {
145+
// it is a parsing error
146+
error = "Parse error";
147+
} else if (response instanceof OtpErlangTuple) {
148+
OtpErlangObject[] elements = ((OtpErlangTuple) response).elements();
149+
150+
// is it an uncaught exception?
151+
if (elements.length == 2
152+
&& elements[0] instanceof OtpErlangAtom
153+
&& ((OtpErlangAtom) elements[0]).atomValue().equals("EXIT")) {
154+
error = "Uncaught exception: " + elements[1];
155+
}
156+
}
157+
158+
if (error == null) {
159+
myEvalCallback.evaluated(ErlangXValueFactory.create(response));
160+
} else {
161+
myEvalCallback.errorOccurred(error);
162+
}
138163
}
139164
}
140165

@@ -178,6 +203,12 @@ public void breakpointIsSet(String module, int line) {
178203

179204
@Override
180205
public void breakpointReached(final OtpErlangPid pid, List<ErlangProcessSnapshot> snapshots) {
206+
if (ignoreNextBreakpointReachedEvent) {
207+
// see the comment about ignoreNextBreakpointReachedEvent
208+
ignoreNextBreakpointReachedEvent = false;
209+
return;
210+
}
211+
181212
ErlangProcessSnapshot processInBreakpoint = ContainerUtil.find(snapshots, erlangProcessSnapshot -> erlangProcessSnapshot.getPid().equals(pid));
182213
assert processInBreakpoint != null;
183214
ErlangSourcePosition breakPosition = ErlangSourcePosition.create(myLocationResolver, processInBreakpoint);

0 commit comments

Comments
 (0)