S-JIS[2013-01-27] 変更履歴

EclipseプラグインDMDLエディター(入力補完)

Eclipseプラグイン開発自作DMDLエディターで入力補完できるようにしてみる。


概要

入力補完(コンテンツアシスト)は、入力候補(キーワード)の一覧が出て、そこから選択して入力することができる機能。
WindowsのEclipseの場合はCtrl+Space、Linuxの場合はAlt+「/」で入力候補一覧が出る。


とりあえず、無条件にキーワード(DMDLのデータ型)一覧を出すように作ってみる。
(理想的には、カーソル位置が何を入力する場所かを推測して、その部分に合致する候補だけ出るべき)

DMDLContentAssistProcessor.java

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は、カーソルのある位置。

CompletionProposalのコンストラクターの引数
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を返しておけばよい。


DMDLConfiguration.java

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

Eclipseプラグインへ戻る / Eclipseへ戻る / 技術メモへ戻る
メールの送信先:ひしだま