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; }