/* * 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.github.sdbg.debug.ui.internal.view; import com.github.sdbg.debug.core.SDBGLaunchConfigWrapper; import com.github.sdbg.utilities.ResourceUtil; import java.net.URI; import java.net.URISyntaxException; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; 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; // 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() { IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(filePath); if (resource instanceof IFile) { return (IFile) resource; } 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; public DebuggerPatternMatchListener() { } @Override public void connect(TextConsole console) { this.console = console; } @Override public void disconnect() { this.console = null; } @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 } } protected IResource getResource() { if (console instanceof ProcessConsole) { ProcessConsole processConsole = (ProcessConsole) console; IProcess process = processConsole.getProcess(); if (process.getLaunch() != null) { SDBGLaunchConfigWrapper wrapper = new SDBGLaunchConfigWrapper( process.getLaunch().getLaunchConfiguration()); return wrapper.getApplicationResource(); } } return null; } private IFile getIFileForAbsolutePath(String pathStr) { return ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(new Path(pathStr)); } private Location parseForLocation(String url, String lineStr) { final String chromeExt = "chrome-extension://"; int line; try { line = Integer.parseInt(lineStr); } catch (NumberFormatException nfe) { return null; } try { String filePath; // /Users/foo/dart/serverapp/serverapp.dart // file:///Users/foo/dart/webapp2/webapp2.dart // http://0.0.0.0:3030/webapp/webapp.dart // package:abc/abc.dart // chrome-extension://kcjgcakhgelcejampmijgkjkadfcncjl/spark.dart // resolve package: urls to file: urls //&&& // if (DartCore.isPackageSpec(url)) { // url = resolvePackageUri(url); // } if (url == null) { return null; } // Special case Chrome extension paths. if (url.startsWith(chromeExt)) { url = url.substring(chromeExt.length()); if (url.indexOf('/') != -1) { url = url.substring(url.indexOf('/') + 1); } } // Handle both fully absolute path names and http: urls. if (url.startsWith("/")) { IFile file = getIFileForAbsolutePath(url); if (file != null) { filePath = file.getFullPath().toPortableString(); } else { return null; } } else if (url.startsWith("file:")) { IFile file = getIFileForAbsolutePath(new URI(url).getPath()); if (file != null) { filePath = file.getFullPath().toPortableString(); } else { return null; } } else if (url.indexOf(':') == -1) { // handle relative file path filePath = resolveRelativePath(url); } else { filePath = new URI(url).getPath(); } // dart: if (filePath == null) { return null; } else { return new Location(filePath, line); } } catch (URISyntaxException e) { return null; } } private String resolvePackageUri(String url) { IResource resource = getResource(); if (resource != null) { IFile file = null; // &&& DartCore.getProjectManager().resolvePackageUri(resource, url); if (file != null) { return file.getLocation().toFile().toURI().toString(); } else { return null; } } return null; } private String resolveRelativePath(String url) { IResource resource = getResource(); if (resource != null) { IResource file = resource.getParent().findMember(url); if (file != null) { return file.getLocation().toPortableString(); } else { return null; } } return null; } }