package monolipse.nunit.views;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import monolipse.core.foundation.WorkspaceUtilities;
import monolipse.nunit.NUnitPlugin;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
public class StackTraceViewer {
private static final Pattern MONO_STACK_PATTERN = Pattern.compile("in\\s(.+\\.(boo|cs|js)):(\\d+)");
private static final Pattern JAVA_STACK_PATTERN = Pattern.compile("\\((.+\\.(boo|cs|js)):(\\d+)\\)");
private static final Pattern COMPILER_OUTPUT_PATTERN = Pattern.compile("\\b(.+\\.(boo|cs|js))\\((\\d+),\\d+\\)");
private Link _traceView;
private ScrolledComposite _composite;
public StackTraceViewer(Composite parent) {
_composite = new ScrolledComposite(parent, SWT.V_SCROLL|SWT.H_SCROLL|SWT.FLAT);
_composite.setExpandHorizontal(true);
_composite.setExpandVertical(true);
_composite.setAlwaysShowScrollBars(true);
_traceView = new Link(_composite, SWT.MULTI|SWT.FLAT);
//_traceView.setEditable(false);
_traceView.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
String[] parts = event.text.split(":");
String path = parts[0];
String line = parts[1];
revealInEditor(WorkspaceUtilities.getFile(path), Integer.parseInt(line));
}
});
_composite.setContent(_traceView);
}
private void revealInEditor(IFile file, int lineNumber) {
final IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
if (null != page) {
try {
IEditorPart editorPart = IDE.openEditor(page, file, true);
selectLine(editorPart, lineNumber);
} catch (PartInitException e) {
NUnitPlugin.logException(e);
}
}
}
private void selectLine(IEditorPart editorPart, int lineNumber) {
if (lineNumber > 0 && editorPart instanceof ITextEditor) {
ITextEditor textEditor = (ITextEditor)editorPart;
IEditorInput input = editorPart.getEditorInput();
int offset = 0;
int length = 0;
IDocumentProvider provider = textEditor.getDocumentProvider();
try {
provider.connect(input);
} catch (CoreException e) {
// unable to link
NUnitPlugin.logException(e);
return;
}
IDocument document = provider.getDocument(input);
try {
IRegion region= document.getLineInformation(lineNumber - 1);
offset = region.getOffset();
length = region.getLength();
} catch (BadLocationException e) {
// unable to link
NUnitPlugin.logException(e);
}
provider.disconnect(input);
if (offset >= 0 && length >=0) {
textEditor.selectAndReveal(offset, length);
}
}
}
public void setStackTrace(String trace) {
_traceView.setText(createHyperLinks(trace));
_composite.setMinSize(_traceView.computeSize(SWT.DEFAULT, SWT.DEFAULT));
}
public Control getControl() {
return _composite;
}
public void setBackground(Color background) {
_traceView.setBackground(background);
}
private String createHyperLinks(String trace) {
if (0 == trace.length()) return trace;
return createHyperLinks(COMPILER_OUTPUT_PATTERN,
createHyperLinks(MONO_STACK_PATTERN,
createHyperLinks(JAVA_STACK_PATTERN, trace)));
}
private String createHyperLinks(Pattern pattern, String trace) {
final Matcher matcher = pattern.matcher(trace);
StringBuffer buffer = new StringBuffer();
while (matcher.find()) {
String fname = matcher.group(1);
final IFile file = WorkspaceUtilities.getFileForLocation(fname);
String lineNumber = matcher.group(3);
String replacement = null == file
? ""
: "<a href=\"" + file.getFullPath().toString() + ":" + lineNumber + "\">" + file.getName() + ":" + lineNumber + "</a>";
matcher.appendReplacement(buffer, replacement);
}
matcher.appendTail(buffer);
return buffer.toString();
}
}