Skip to content

Commit 71814c4

Browse files
committed
Improving the expression evaluator
* 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 occuring in an Erlang process right after evaluating an expression in that process. Better ideas welcome! * checking whether the evaluation resulted in an error, and nicely formatting it in if that's the case
1 parent 004db36 commit 71814c4

File tree

2 files changed

+49
-7
lines changed

2 files changed

+49
-7
lines changed

src/org/intellij/erlang/debugger/node/ErlangDebuggerNode.java

+2
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ public int getLocalDebuggerPort() {
6969
return myLocalDebuggerPort;
7070
}
7171

72+
public OtpErlangPid getLastSuspendedPid() { return myLastSuspendedPid; }
73+
7274
public void stop() {
7375
myStopped.set(true);
7476
}

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

+47-7
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 in the same process right after evaluating an expression - better ideas welcome!
92+
private OtpErlangPid ignoreNextBreakpointReachedEventFor = null;
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,20 +130,48 @@ 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 ignoreNextBreakpointReachedEventFor
135+
ignoreNextBreakpointReachedEventFor = myDebuggerNode.getLastSuspendedPid();
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 = maybeExtractErrorFromEvaluationResponse(response);
143+
144+
if (error == null) {
145+
myEvalCallback.evaluated(ErlangXValueFactory.create(response));
146+
}
147+
else {
148+
myEvalCallback.errorOccurred(error);
149+
}
138150
}
139151
}
140152

153+
// Parses the response from an evaluation and determines whether it's an error
154+
// response or not; if it is an error, formats it as a displayable string, if
155+
// it's not, just returns null
156+
private static String maybeExtractErrorFromEvaluationResponse(OtpErlangObject response) {
157+
// is it a parsing error?
158+
if (response instanceof OtpErlangAtom && ((OtpErlangAtom) response).atomValue().equals("Parse error")) {
159+
return "Parse error";
160+
}
161+
162+
// is it an uncaught exception?
163+
if (response instanceof OtpErlangTuple) {
164+
OtpErlangObject[] elements = ((OtpErlangTuple) response).elements();
165+
if (elements.length == 2
166+
&& elements[0] instanceof OtpErlangAtom
167+
&& ((OtpErlangAtom) elements[0]).atomValue().equals("EXIT")) {
168+
return "Uncaught exception: " + elements[1];
169+
}
170+
}
171+
172+
return null;
173+
}
174+
141175
@Override
142176
public void debuggerStarted() {
143177
getSession().reportMessage("Debug process started", MessageType.INFO);
@@ -177,7 +211,13 @@ public void breakpointIsSet(String module, int line) {
177211
}
178212

179213
@Override
180-
public void breakpointReached(final OtpErlangPid pid, List<ErlangProcessSnapshot> snapshots) {
214+
public synchronized void breakpointReached(final OtpErlangPid pid, List<ErlangProcessSnapshot> snapshots) {
215+
if (pid.equals(ignoreNextBreakpointReachedEventFor)) {
216+
// see the comment about ignoreNextBreakpointReachedEventFor
217+
ignoreNextBreakpointReachedEventFor = null;
218+
return;
219+
}
220+
181221
ErlangProcessSnapshot processInBreakpoint = ContainerUtil.find(snapshots, erlangProcessSnapshot -> erlangProcessSnapshot.getPid().equals(pid));
182222
assert processInBreakpoint != null;
183223
ErlangSourcePosition breakPosition = ErlangSourcePosition.create(myLocationResolver, processInBreakpoint);

0 commit comments

Comments
 (0)