package org.erlide.test_support.ui.trace;
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.jface.text.ITextViewer;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector;
import org.eclipse.jface.text.hyperlink.IHyperlink;
import org.erlide.ui.util.ErlModelUtils;
import org.erlide.util.ErlLogger;
public class HyperlinkDetector extends AbstractHyperlinkDetector {
public HyperlinkDetector() {
}
@Override
public IHyperlink[] detectHyperlinks(final ITextViewer textViewer,
final IRegion region, final boolean canShowMultipleHyperlinks) {
if (region == null || textViewer == null) {
return null;
}
final IDocument document = textViewer.getDocument();
final int offset = region.getOffset();
if (document == null) {
return null;
}
IRegion lineInfo;
String line;
try {
lineInfo = document.getLineInformationOfOffset(offset);
line = document.get(lineInfo.getOffset(), lineInfo.getLength());
} catch (final BadLocationException ex) {
return null;
}
final int offsetInLine = offset - lineInfo.getOffset();
IRegion r = getLink(line, offsetInLine);
if (r != null) {
final String text = line.substring(r.getOffset(),
r.getOffset() + r.getLength());
r = new Region(lineInfo.getOffset() + r.getOffset(), r.getLength());
return new IHyperlink[] { new TraceHyperlink(r, text) };
}
return null;
}
private IRegion getLink(final String line, final int offsetInLine) {
final int offset = 33;
int pos = line.indexOf(" ->", offset);
if (pos < 0) {
if (line.indexOf('(') < 0) {
return null;
}
pos = line.length();
}
return new Region(offset, pos - offset);
}
private static class TraceHyperlink implements IHyperlink {
private final IRegion region;
private final String text;
public TraceHyperlink(final IRegion region, final String text) {
this.text = text;
this.region = region;
}
@Override
public String getTypeLabel() {
return null;
}
@Override
public String getHyperlinkText() {
return text;
}
@Override
public void open() {
final String[] mf = text.split(":");
final String module = mf[0];
String function = mf[1];
int arity;
final int slash = function.indexOf('/');
if (function.matches("'-[^/]+/[0-9]+-fun-.*")) {
arity = Integer.parseInt(function.substring(slash + 1,
function.indexOf('-', slash)));
function = function.substring(2, slash);
} else {
if (slash < 0) {
final int pos = function.indexOf('(');
arity = countArgs(function.substring(pos + 1, function.length() - 1));
function = function.substring(0, pos);
} else {
final String args = function.substring(slash + 1);
arity = Integer.parseInt(args);
function = function.substring(0, slash);
}
}
try {
ErlModelUtils.openMFA(module, function, arity);
} catch (final CoreException e) {
ErlLogger.warn("Could not open %s:%s/%d", module, function, arity);
}
}
private int countArgs(final String args) {
if (args.length() == 0) {
return 0;
}
return countArgs(args, 0, 1, 0);
}
private int countArgs(final String args, final int i0, final int n, final int p) {
int i = i0;
if (args.length() == i) {
return n;
}
final char c = args.charAt(i++);
if (c == '[') {
return countArgs(args, i, n, p + 1);
} else if (c == '{') {
return countArgs(args, i, n, p + 1);
} else if (c == '}') {
return countArgs(args, i, n, p - 1);
} else if (c == ']') {
return countArgs(args, i, n, p - 1);
} else if (c == ',') {
if (p == 0) {
return countArgs(args, i, n + 1, p);
}
return countArgs(args, i, n, p);
} else {
return countArgs(args, i, n, p);
}
}
@Override
public IRegion getHyperlinkRegion() {
return region;
}
}
}