Eclipseのプラグイン開発の自作DMDLエディターで入力補完できるようにしてみる。
|
入力補完(コンテンツアシスト)は、入力候補(キーワード)の一覧が出て、そこから選択して入力することができる機能。
WindowsのEclipseの場合はCtrl+Space、Linuxの場合はAlt+「/」で入力候補一覧が出る。
とりあえず、無条件にキーワード(DMDLのデータ型)一覧を出すように作ってみる。
(理想的には、カーソル位置が何を入力する場所かを推測して、その部分に合致する候補だけ出るべき)
IContentAssistProcessorインターフェースを実装してキーワード一覧を用意する。
import java.util.ArrayList; import java.util.List; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.contentassist.CompletionProposal; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.contentassist.IContentAssistProcessor; import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.jface.text.contentassist.IContextInformationValidator;
public class DMDLContentAssistProcessor implements IContentAssistProcessor {
protected static final String[] TYPE_ASSIST = { "INT", "LONG", "FLOAT", "DOUBLE", "TEXT", "DECIMAL", "DATE", "DATETIME", "BOOLEAN", "BYTE", "SHORT" };
@Override
public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
List<ICompletionProposal> list = new ArrayList<ICompletionProposal>(TYPE_ASSIST.length);
for (String s : TYPE_ASSIST) {
list.add(new CompletionProposal(s, offset, 0, s.length()));
}
return list.toArray(new ICompletionProposal[list.size()]);
}
キーワード一覧はICompletionProposalの配列にして返す。
computeCompletionProposals()の引数のoffsetは、カーソルのある位置。
| 1 | replacementString | 置換(入力補完)される文字列。 |
| 2 | replacementOffset | 文字列が置換(挿入)される開始位置。 |
| 3 | replacementLength | 元からあった文字列を削除する文字数。 |
| 4 | cursorPosition | 置換後のカーソルの位置。(ずらす文字数) |
@Override
public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
return null;
}
@Override
public char[] getCompletionProposalAutoActivationCharacters() {
return null;
}
@Override
public char[] getContextInformationAutoActivationCharacters() {
return null;
}
@Override
public String getErrorMessage() {
return null;
}
@Override
public IContextInformationValidator getContextInformationValidator() {
return null;
}
}
その他のメソッドは(何をするものなのか分からないので(爆)、とりあえず)nullを返しておけばよい。
SourceViewerConfigurationクラスで上記のDMDLContentAssistProcessorを登録する。
import org.eclipse.jface.text.contentassist.ContentAssistant; import org.eclipse.jface.text.contentassist.IContentAssistant;
public class DMDLConfiguration extends SourceViewerConfiguration {
〜
@Override
public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {
ContentAssistant assistant = new ContentAssistant();
DMDLContentAssistProcessor processor = new DMDLContentAssistProcessor();
assistant.setContentAssistProcessor(processor, DMDLPartitionScanner.DMDL_BLOCK);
assistant.install(sourceViewer);
return assistant;
}
}
ContentAssistProcessorをContentAssistantに登録する際にはパーティション名を指定する。
(たぶん、そのパーティションでだけコンテンツアシストが表示される)
『Eclipse プラグイン開発 徹底攻略』(p.180)には「入力補完処理を呼び出すアクションをエディターに登録する必要がある」と書かれているんだけど、(Eclipse3.7では)特に登録しなくても補完機能は働いた。
入力補完は、カーソル位置に途中まで入力されている文字列があったら、それに該当するものだけ候補として出したい。
また、DMDLのデータ型の位置は必ず「:」の後になるはずなので、それも判定に加えてみる。
@Override
public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
IDocument document = viewer.getDocument();
List<ICompletionProposal> list = computeDataType(document, offset);
if (list != null && !list.isEmpty()) {
return list.toArray(new ICompletionProposal[list.size()]);
}
return null;
}
protected List<ICompletionProposal> computeDataType(IDocument document, int offset) {
// 単語の先頭を探す
int n = offset - 1;
for (; n >= 0; n--) {
char c;
try {
c = document.getChar(n);
} catch (BadLocationException e) {
break;
}
if ('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z') {
continue;
} else {
break;
}
}
// 「:」を探す
for (int i = n; i >= 0; i--) {
char c;
try {
c = document.getChar(i);
} catch (BadLocationException e) {
break;
}
if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
continue;
} else if (c == ':') {
int start = n + 1;
int len = offset - start;
String text;
try {
text = document.get(start, len).toUpperCase();
} catch (BadLocationException e) {
return null;
}
List<ICompletionProposal> list = new ArrayList<ICompletionProposal>();
for (String s : TYPE_ASSIST) {
if (s.startsWith(text)) {
list.add(new CompletionProposal(s, start, len, s.length()));
}
}
return list;
} else {
break;
}
}
return null;
}