Eclipseのプラグイン開発のJDTでのハイパーリンクについて。
|
Javaエディターで独自のハイパーリンクを行いたい。
(Javaエディター上のハイパーリンクから自分が指定したファイルへジャンプさせたい)
しかし、以前もハイパーリンクを作ったが、この方式ではIHyperlinkDetectorのインスタンス生成をSourceViewerConfigurationで行っている為、独自テキストエディターを作る場合にしか使えない。
そこで、IHyperlinkDetectorの定義をextensionで行う。
依存プラグインは「org.eclipse.ui.workbench.texteditor」。
まず、ハイパーリンクを出すことが可能かどうかを判定するクラスを作成する。
JDTのハイパーリンクはorg.eclipse.jdt.internal.ui.javaeditor.JavaElementHyperlinkDetectorが使われているようだが、例によってこのクラスは非公開(Eclipseプラグインではたとえpublicであっても、明示的に“公開”が指定されているクラスでないと使用できない)なので直接使用することは出来ない。
でも非常に参考になる。
import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.ITypeRoot; import org.eclipse.jdt.core.JavaModelException; 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.eclipse.ui.IEditorInput; import org.eclipse.ui.texteditor.ITextEditor;
public class MyHyperlinkDetector extends AbstractHyperlinkDetector {
@Override
public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) {
// ハイパーリンクを表示するエディターを取得
ITextEditor editor = (ITextEditor) getAdapter(ITextEditor.class);
if (editor == null) {
return null;
}
// IJavaElementを取得
IEditorInput input = editor.getEditorInput();
IJavaElement element = (IJavaElement) input.getAdapter(IJavaElement.class);
// ドキュメントを取得
IDocument document = editor.getDocumentProvider().getDocument(input);
// マウスカーソルの指している位置の単語を取得
int offset = region.getOffset();
IRegion word = findWord(document, offset);
if (word == null || word.getLength() == 0) {
return null;
}
// 単語の位置のコードを取得
IJavaElement[] codes;
try {
ITypeRoot root = (ITypeRoot) element.getAdapter(ITypeRoot.class);
codes = root.codeSelect(word.getOffset(), word.getLength());
} catch (JavaModelException e) {
return null;
}
for (IJavaElement code : codes) {
// コードの種類毎に分岐
int elementType = code.getElementType();
switch (elementType) {
case IJavaElement.TYPE: //クラス
IHyperlink[] tr = detectClassHyperlinks((IType) code, word);
if (tr != null) {
return tr;
}
break;
case IJavaElement.FIELD: //フィールド
IHyperlink[] fr = detectFieldHyperlinks((IField) code, word);
if (fr != null) {
return fr;
}
break;
case IJavaElement.METHOD: //メソッド
IHyperlink[] mr = detectMethodHyperlinks((IMethod) code, word);
if (mr != null) {
return mr;
}
break;
}
}
return null;
}
// @see org.eclipse.jdt.internal.ui.text.JavaWordFinder#findWord()
private static IRegion findWord(IDocument document, int offset) {
int start = -2;
int end = -1;
try {
int pos;
for (pos = offset; pos >= 0; pos--) {
char c = document.getChar(pos);
if (!Character.isJavaIdentifierPart(c)) {
break;
}
}
start = pos;
pos = offset;
for (int length = document.getLength(); pos < length; pos++) {
char c = document.getChar(pos);
if (!Character.isJavaIdentifierPart(c)) {
break;
}
}
end = pos;
} catch (BadLocationException e) {
}
if (start >= -1 && end > -1) {
if (start == offset && end == offset) {
return new Region(offset, 0);
}
if (start == offset) {
return new Region(start, end - start);
} else {
return new Region(start + 1, end - start - 1);
}
} else {
return null;
}
}
private IHyperlink[] detectClassHyperlinks(IType type, IRegion region) {
String name = type.getElementName();
〜
return new IHyperlink[] { new MyHyperlink(name, region) };
}
private IHyperlink[] detectFieldHyperlinks(IField field, IRegion region) {
String name = field.getElementName();
〜
return new IHyperlink[] { new MyHyperlink(name, region) };
}
private IHyperlink[] detectMethodHyperlinks(IMethod method, IRegion region) {
String name = method.getElementName();
〜
return new IHyperlink[] { new MyHyperlink(name, region) };
}
}
※IJavaElementを使わず、直接ASTNodeを使えば、例えば文字列等でも判定することが出来る。
マニフェストファイルのextensionでハイパーリンクの指定を行う。
<extension
point="org.eclipse.ui.workbench.texteditor.hyperlinkDetectors">
<hyperlinkDetector
activate="true"
class="jp.hishidama.eclipse_plugin.dmdl_editor.jdt.hyperlink.MyHyperlinkDetector"
description="Open Declared DMDL"
id="dmdl-editor-plugin.hyperlinkDetector.jdt.open-declaration"
name="Open Declared DMDL"
targetId="org.eclipse.jdt.ui.javaCode">
</hyperlinkDetector>
</extension>
targetIdに「org.eclipse.jdt.ui.javaCode」を指定することで、Javaエディターの場合だけ呼ばれるようになる。
import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.hyperlink.IHyperlink;
public class MyHyperlink implements IHyperlink {
private String name;
private IRegion region;
public MyHyperlink(String name, IRegion region) {
this.name = name;
this.region = region;
}
@Override
public IRegion getHyperlinkRegion() {
return region;
}
@Override
public String getTypeLabel() {
return "Open Declared DMDL";
}
@Override
public String getHyperlinkText() {
return "Open Declared DMDL";
}
Javaエディターでクラス名やフィールド名・メソッド名のハイパーリンクをしようとすると、既存のハイパーリンクと被ってしまう。
その場合はポップアップメニューが出て、動作をユーザーが選択できる。
その際のメニュー名はgetHyperlinkText()で返した文字列になる。
@Override
public void open() {
〜
}
}