Skip to content

Commit

Permalink
[GR-5310] Chrome Inspector should work in Visual Studio Code.
Browse files Browse the repository at this point in the history
  • Loading branch information
dbalek committed Jan 19, 2018
1 parent 6b27df1 commit d0a7d38
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 116 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ public void testBreakpoints() throws Exception {
assertTrue(tester.compareReceivedMessages(
"{\"method\":\"Debugger.scriptParsed\",\"params\":{\"endLine\":0,\"scriptId\":\"0\",\"endColumn\":0,\"startColumn\":0,\"startLine\":0,\"length\":0,\"executionContextId\":" + id + ",\"url\":\"" + SL_BUILTIN_URI + "\",\"hash\":\"ffffffffffffffffffffffffffffffffffffffff\"}}\n" +
"{\"method\":\"Debugger.scriptParsed\",\"params\":{\"endLine\":18,\"scriptId\":\"1\",\"endColumn\":1,\"startColumn\":0,\"startLine\":0,\"length\":245,\"executionContextId\":" + id + ",\"url\":\"" + slTestURI + "\",\"hash\":\"f8058ed0f3c2f0acf3e37e59f953127afdba90e5\"}}\n" +
"{\"method\":\"Debugger.breakpointResolved\",\"params\":{\"breakpointId\":\"1\",\"locations\":[{\"scriptId\":\"1\",\"columnNumber\":0,\"lineNumber\":11}]}}\n" +
"{\"method\":\"Debugger.paused\",\"params\":{\"reason\":\"other\",\"hitBreakpoints\":[\"1\"]," +
"\"callFrames\":[{\"callFrameId\":\"0\",\"functionName\":\"factorial\"," +
"\"scopeChain\":[{\"name\":\"factorial\",\"type\":\"local\",\"object\":{\"description\":\"factorial\",\"type\":\"object\",\"objectId\":\"1\"}}," +
Expand Down Expand Up @@ -269,6 +270,8 @@ public void testBreakpointDeactivation() throws Exception {
assertTrue(tester.compareReceivedMessages(
"{\"method\":\"Debugger.scriptParsed\",\"params\":{\"endLine\":0,\"scriptId\":\"0\",\"endColumn\":0,\"startColumn\":0,\"startLine\":0,\"length\":0,\"executionContextId\":" + id + ",\"url\":\"" + SL_BUILTIN_URI + "\",\"hash\":\"ffffffffffffffffffffffffffffffffffffffff\"}}\n" +
"{\"method\":\"Debugger.scriptParsed\",\"params\":{\"endLine\":11,\"scriptId\":\"1\",\"endColumn\":1,\"startColumn\":0,\"startLine\":0,\"length\":144,\"executionContextId\":" + id + ",\"url\":\"" + slTestURI + "\",\"hash\":\"ee148976fc7d6f36fc01da4bfba1c3f3ff485978\"}}\n" +
"{\"method\":\"Debugger.breakpointResolved\",\"params\":{\"breakpointId\":\"1\",\"locations\":[{\"scriptId\":\"1\",\"columnNumber\":0,\"lineNumber\":9}]}}\n" +
"{\"method\":\"Debugger.breakpointResolved\",\"params\":{\"breakpointId\":\"2\",\"locations\":[{\"scriptId\":\"1\",\"columnNumber\":0,\"lineNumber\":10}]}}\n" +
"{\"method\":\"Debugger.paused\",\"params\":{\"reason\":\"other\",\"hitBreakpoints\":[]," +
"\"callFrames\":[{\"callFrameId\":\"0\",\"functionName\":\"main\"," +
"\"scopeChain\":[{\"name\":\"main\",\"type\":\"local\",\"object\":{\"description\":\"main\",\"type\":\"object\",\"objectId\":\"1\"}}," +
Expand Down Expand Up @@ -464,7 +467,7 @@ public void testNotSuspended() throws Exception {
assertEquals("{\"result\":{\"exceptionDetails\":{\"text\":\"<Not suspended>\"}},\"id\":3}", tester.getMessages(true).trim());
// Try to evaluate:
tester.sendMessage("{\"id\":4,\"method\":\"Runtime.evaluate\",\"params\":{\"expression\":\"app\",\"objectGroup\":\"watch-group\",\"includeCommandLineAPI\":false,\"silent\":true,\"contextId\":" + id + "}}");
assertEquals("{\"result\":{\"result\":{\"value\":\"<Not suspended>\"}},\"id\":4}", tester.getMessages(true).trim());
assertEquals("{\"result\":{\"exceptionDetails\":{\"text\":\"<Not suspended>\"}},\"id\":4}", tester.getMessages(true).trim());
tester.finish();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@
*/
package com.oracle.truffle.tools.chromeinspector;

import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.json.JSONArray;
import org.json.JSONObject;
Expand All @@ -36,17 +38,22 @@
import com.oracle.truffle.api.debug.DebuggerSession;

import com.oracle.truffle.tools.chromeinspector.commands.Params;
import com.oracle.truffle.tools.chromeinspector.server.CommandProcessException;
import com.oracle.truffle.tools.chromeinspector.types.Location;
import com.oracle.truffle.tools.chromeinspector.types.Script;

final class BreakpointsHandler {

private long lastID = 0;

private final DebuggerSession ds;
private final ScriptsHandler slh;
private final Map<Breakpoint, Long> bpIDs = new HashMap<>();
private final Map<Long, BPInfo> urlBPs = new HashMap<>();

BreakpointsHandler(DebuggerSession ds) {
BreakpointsHandler(DebuggerSession ds, ScriptsHandler slh) {
this.ds = ds;
this.slh = slh;
}

String getId(Breakpoint bp) {
Expand All @@ -60,31 +67,40 @@ String getId(Breakpoint bp) {
}
}

Params createURLBreakpoint(URI uri, int line, int column, String condition) {
Breakpoint bp = Breakpoint.newBuilder(uri).lineIs(line).build();
if (column > 0) {
// TODO set breakpoint's column
}
if (condition != null && !condition.isEmpty()) {
bp.setCondition(condition);
}
bp = ds.install(bp);
Params createURLBreakpoint(Object url, int line, int column, String condition) throws CommandProcessException {
long id;
synchronized (bpIDs) {
id = ++lastID;
bpIDs.put(bp, id);
urlBPs.put(id, new BPInfo(url, line, column, condition));
}
// TODO: Get resolved info
// Location loc = new Location(, line, column);
JSONArray locations = new JSONArray();
slh.getScripts().stream().filter(script -> url instanceof Pattern ? ((Pattern) url).matcher(script.getUrl()).matches() : url.equals(script.getUrl())).forEach(script -> {
Breakpoint bp = Breakpoint.newBuilder(script.getSource()).lineIs(line).build();
if (column > 0) {
// TODO set breakpoint's column
}
if (condition != null && !condition.isEmpty()) {
bp.setCondition(condition);
}
bp = ds.install(bp);
synchronized (bpIDs) {
bpIDs.put(bp, id);
}
locations.put(new Location(script.getId(), line, column).toJSON());
});
JSONObject json = new JSONObject();
json.put("breakpointId", Long.toString(id));
json.put("locations", new JSONArray());
json.put("locations", locations);
return new Params(json);
}

Params createBreakpoint(Location location, URI uri, String condition) {
Breakpoint bp = Breakpoint.newBuilder(uri).lineIs(location.getLine()).build();
if (condition != null) {
Params createBreakpoint(Location location, String condition) throws CommandProcessException {
Script script = slh.getScript(location.getScriptId());
if (script == null) {
throw new CommandProcessException("No script with id '" + location.getScriptId() + "'");
}
Breakpoint bp = Breakpoint.newBuilder(script.getSource()).lineIs(location.getLine()).build();
if (condition != null && !condition.isEmpty()) {
bp.setCondition(condition);
}
bp = ds.install(bp);
Expand All @@ -102,34 +118,75 @@ Params createBreakpoint(Location location, URI uri, String condition) {
}

boolean removeBreakpoint(String idStr) {
long id;
boolean bpRemoved = false;
try {
id = Long.parseLong(idStr);
} catch (NumberFormatException nfex) {
return false;
}
Breakpoint bp = null;
synchronized (bpIDs) {
Iterator<Map.Entry<Breakpoint, Long>> bpEntryIt = bpIDs.entrySet().iterator();
while (bpEntryIt.hasNext()) {
Map.Entry<Breakpoint, Long> bpEntry = bpEntryIt.next();
if (id == bpEntry.getValue().longValue()) {
bp = bpEntry.getKey();
bpEntryIt.remove();
break;
long id = Long.parseLong(idStr);
synchronized (bpIDs) {
Iterator<Map.Entry<Breakpoint, Long>> bpEntryIt = bpIDs.entrySet().iterator();
while (bpEntryIt.hasNext()) {
Map.Entry<Breakpoint, Long> bpEntry = bpEntryIt.next();
if (id == bpEntry.getValue().longValue()) {
Breakpoint bp = bpEntry.getKey();
if (bp != null) {
bp.dispose();
}
bpEntryIt.remove();
bpRemoved = true;
}
}
if (urlBPs.remove(id) != null) {
bpRemoved = true;
}
}
} catch (NumberFormatException nfex) {
}
if (bp == null) {
return false;
}
bp.dispose();
return true;
return bpRemoved;
}

void createOneShotBreakpoint(Location location, URI uri) {
Breakpoint bp = Breakpoint.newBuilder(uri).lineIs(location.getLine()).oneShot().build();
void createOneShotBreakpoint(Location location) throws CommandProcessException {
Script script = slh.getScript(location.getScriptId());
if (script == null) {
throw new CommandProcessException("No script with id '" + location.getScriptId() + "'");
}
Breakpoint bp = Breakpoint.newBuilder(script.getSource()).lineIs(location.getLine()).oneShot().build();
ds.install(bp);
}

List<Params> resolveURLBreakpoints(Script script) {
List<Params> resolvedBPLocations = new ArrayList<>();
urlBPs.entrySet().forEach(urlBPEntry -> {
BPInfo urlBP = urlBPEntry.getValue();
if (urlBP.url instanceof Pattern ? ((Pattern) urlBP.url).matcher(script.getUrl()).matches() : urlBP.url.equals(script.getUrl())) {
Breakpoint bp = Breakpoint.newBuilder(script.getSource()).lineIs(urlBP.line).build();
if (urlBP.condition != null && !urlBP.condition.isEmpty()) {
bp.setCondition(urlBP.condition);
}
bp = ds.install(bp);
synchronized (bpIDs) {
bpIDs.put(bp, urlBPEntry.getKey());
}
JSONObject json = new JSONObject();
json.put("breakpointId", Long.toString(urlBPEntry.getKey()));
JSONArray locations = new JSONArray();
locations.put(new Location(script.getId(), urlBP.line, urlBP.column).toJSON());
json.put("locations", locations);
resolvedBPLocations.add(new Params(json));
}
});
return resolvedBPLocations;
}

private static final class BPInfo {
private Object url;
private int line;
private int column;
private String condition;

public BPInfo(Object url, int line, int column, String condition) {
this.url = url;
this.line = line;
this.column = column;
this.condition = condition;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
Expand Down Expand Up @@ -63,6 +64,12 @@ public Script getScript(int id) {
}
}

public List<Script> getScripts() {
synchronized (sourceIDs) {
return Collections.unmodifiableList(scripts);
}
}

void addLoadScriptListener(LoadScriptListener listener) {
listeners.add(listener);
List<Script> scriptsToNotify;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@

import java.io.File;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
Expand Down Expand Up @@ -124,7 +122,7 @@ private void doEnable() {
ds = tdbg.startSession(new SuspendedCallbackImpl());
ds.setSteppingFilter(SuspensionFilter.newBuilder().ignoreLanguageContextInitialization(true).includeInternal(false).build());
slh = context.getScriptsHandler();
bph = new BreakpointsHandler(ds);
bph = new BreakpointsHandler(ds, slh);
// globalScope = new Scope("global", null, null, null); // TODO
}

Expand Down Expand Up @@ -173,6 +171,13 @@ public void setPauseOnExceptions(String state) {

}

@Override
public Params getPossibleBreakpoints(Location start, Location end, boolean restrictToFunction) {
JSONObject json = new JSONObject();
json.put("locations", new JSONArray());
return new Params(json);
}

@Override
public Params getScriptSource(String scriptId) throws CommandProcessException {
if (scriptId == null) {
Expand Down Expand Up @@ -353,18 +358,16 @@ public void setBreakpointsActive(Optional<Boolean> active) throws CommandProcess

@Override
public Params setBreakpointByUrl(String url, String urlRegex, int line, int column, String condition) throws CommandProcessException {
if (url == null && urlRegex == null) {
if (url.isEmpty() && urlRegex.isEmpty()) {
throw new CommandProcessException("Must specify either url or urlRegex.");
}
if (line <= 0) {
throw new CommandProcessException("Must specify line number.");
}
if (url != null) {
URI uri = getScriptURIForBP(url);
return bph.createURLBreakpoint(uri, line, column, condition);
if (!url.isEmpty()) {
return bph.createURLBreakpoint(url, line, column, condition);
} else {
// TODO
throw new CommandProcessException("urlRegex not supported at the moment.");
return bph.createURLBreakpoint(Pattern.compile(urlRegex), line, column, condition);
}
}

Expand All @@ -373,11 +376,7 @@ public Params setBreakpoint(Location location, String condition) throws CommandP
if (location == null) {
throw new CommandProcessException("Must specify location.");
}
Script script = slh.getScript(location.getScriptId());
if (script == null) {
throw new CommandProcessException("No script with id '" + location.getScriptId() + "'");
}
return bph.createBreakpoint(location, script.getSource().getURI(), condition);
return bph.createBreakpoint(location, condition);
}

@Override
Expand All @@ -392,11 +391,7 @@ public void continueToLocation(Location location, CommandPostProcessor postProce
if (location == null) {
throw new CommandProcessException("Must specify location.");
}
Script script = slh.getScript(location.getScriptId());
if (script == null) {
throw new CommandProcessException("No script with id '" + location.getScriptId() + "'");
}
bph.createOneShotBreakpoint(location, script.getSource().getURI());
bph.createOneShotBreakpoint(location);
resume(postProcessor);
}

Expand Down Expand Up @@ -495,32 +490,6 @@ public static boolean sourceMatchesBlackboxPatterns(Source source, Pattern[] pat
return false;
}

private static URI getScriptURIForBP(String scripturl) throws CommandProcessException {
int i = 0;
while (i < scripturl.length()) {
char c = scripturl.charAt(i);
if (c == ':') {
break;
} else if (c == '/' || c == '?' || c == '#') {
i = 0;
break;
}
i++;
}
URI uri;
try {
if (i > 0) {
// There is a scheme
uri = ScriptsHandler.getURIFromNiceString(scripturl);
} else {
uri = new URI("file", null, scripturl, null, null);
}
} catch (URISyntaxException use) {
throw new CommandProcessException(use.getMessage());
}
return uri;
}

private class LoadScriptListenerImpl implements LoadScriptListener {

@Override
Expand Down Expand Up @@ -560,6 +529,9 @@ public void loadedScript(Script script) {
Params params = new Params(jsonParams);
Event scriptParsed = new Event("Debugger.scriptParsed", params);
eventHandler.event(scriptParsed);
bph.resolveURLBreakpoints(script).stream().map(locationParams -> new Event("Debugger.breakpointResolved", locationParams)).forEach(breakpointResolved -> {
eventHandler.event(breakpointResolved);
});
}

private CharSequence getSourceMapURL(Source source, int lastLine) {
Expand Down
Loading

0 comments on commit d0a7d38

Please sign in to comment.