/*
* Copyright (c) 2012, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.tools.debug.ui.internal.view;
import com.google.dart.tools.core.internal.util.ResourceUtil;
import com.google.dart.tools.debug.core.source.UriToFileResolver;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
import org.eclipse.debug.ui.console.FileLink;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.ui.console.IPatternMatchListener;
import org.eclipse.ui.console.PatternMatchEvent;
import org.eclipse.ui.console.TextConsole;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
// VM exceptions look like:
//
// Unhandled exception:
// foo
// #1 main (file:///Users/devoncarew/projects/dart/dart/editor/util/debuggertest/cmd_test.dart:30:11)
// Dartium exceptions look like:
//
// Exception: foo
// Stack Trace: #0 List.add (bootstrap_impl:787:7)
// #1 testAnimals (http://127.0.0.1:3030/Users/devoncarew/projects/dart/dart/editor/util/debuggertest/web_test.dart:55:11)
// #2 rotateText.rotateText (http://127.0.0.1:3030/Users/devoncarew/projects/dart/dart/editor/util/debuggertest/web_test.dart:33:14)
/**
* A console pattern match listener that creates hyperlinks in the console for VM and Dartium
* exceptions.
*/
@SuppressWarnings("restriction")
public class DebuggerPatternMatchListener implements IPatternMatchListener {
private static class Location {
private String filePath;
private int line;
public Location(String filePath, int line) {
this.filePath = filePath;
this.line = line;
}
public boolean doesExist() {
return getFile() != null;
}
public IFile getFile() {
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
IFile file = workspaceRoot.getFileForLocation(new Path(filePath));
if (file != null) {
return file;
}
IPath path = new Path(filePath);
return ResourceUtil.getFile(path.toFile());
}
public int getLine() {
return line;
}
@Override
public String toString() {
return "[" + filePath + ":" + line + "]";
}
}
public static String DARTIUM_PATTERN_1 = "\\((\\S+):(\\d+):(\\d+)\\)";
public static String DARTIUM_PATTERN_2 = "\\((\\S+):(\\d+)\\)";
public static String UNITTEST_PATTERN = "^ (\\S*\\.dart) (\\d*)";
private static Pattern dartiumPattern1 = Pattern.compile(DebuggerPatternMatchListener.DARTIUM_PATTERN_1);
private static Pattern dartiumPattern2 = Pattern.compile(DebuggerPatternMatchListener.DARTIUM_PATTERN_2);
private static Pattern unitTestPattern = Pattern.compile(DebuggerPatternMatchListener.UNITTEST_PATTERN);
private TextConsole console;
private UriToFileResolver uriToFileResolver;
public DebuggerPatternMatchListener() {
}
@Override
public void connect(TextConsole console) {
this.console = console;
// get the launched resource
if (console instanceof ProcessConsole) {
ProcessConsole processConsole = (ProcessConsole) console;
IProcess process = processConsole.getProcess();
ILaunch launch = process.getLaunch();
if (launch != null) {
uriToFileResolver = new UriToFileResolver(launch);
}
}
}
@Override
public void disconnect() {
this.console = null;
uriToFileResolver.dispose();
}
@Override
public int getCompilerFlags() {
return 0;
}
@Override
public String getLineQualifier() {
return null;
}
@Override
public String getPattern() {
// (http://127.0.0.1:3030/Users/util/debuggertest/web_test.dart:33:14)
// http://127.0.0.1:8081
// cmd.dart 67:13 main.<fn>.<fn>
// package:unittest/src/test_case.dart 109:30 _run.<fn>
// dart:async/zone.dart 717 _rootRunUnary
return "(\\(.*\\))|( \\S*.dart .*)";
}
@Override
public void matchFound(PatternMatchEvent event) {
if (console == null) {
return;
}
try {
String text = console.getDocument().get(event.getOffset(), event.getLength());
Matcher match = dartiumPattern1.matcher(text);
if (!match.find()) {
match = dartiumPattern2.matcher(text);
if (!match.find()) {
match = unitTestPattern.matcher(text);
if (!match.find()) {
match = null;
}
}
}
if (match != null) {
Location location = parseForLocation(match.group(1), match.group(2));
if (location != null && location.doesExist()) {
console.addHyperlink(
new FileLink(location.getFile(), null, -1, -1, location.getLine()),
event.getOffset() + match.start(1),
match.end(2) - match.start(1));
return;
}
}
} catch (BadLocationException e) {
// don't create a hyperlink
}
}
private Location parseForLocation(String url, String lineStr) {
String filePath = uriToFileResolver.getFileForUri(url);
if (filePath == null) {
return null;
}
int line;
try {
line = Integer.parseInt(lineStr);
} catch (NumberFormatException nfe) {
return null;
}
return new Location(filePath, line);
}
}