EclipsePlug-in使用TextEditor開發自己的編輯器,實現關鍵字高亮和程式碼提示.
阿新 • • 發佈:2019-02-04
最近在開發EclipsePlug, 開發一個SQL程式碼編輯器, 所以就寫一篇文章. 希望對大家有幫助. 讓大家少走彎路. (程式碼可能不能執行, 但關鍵部分都有). 因為程式碼比較多. 所以可能不能一次性上傳完成. 畢竟我還要修改, 空話不多說. 直接上程式碼.
首先是Editor類, 我取名為SQLEditor, 繼承TextEditor:
package com.test.editors; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.formatter.IContentFormatter; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.IViewPart; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.editors.text.TextEditor; import com.zdk.platform.studio.dbassistant.codeassistent.ColorManager; import com.zdk.platform.studio.dbassistant.codeassistent.SQLConfiguration; import com.zdk.platform.studio.dbassistant.codeassistent.SQLDocumentProvider; /** * 類說明: SQL語句編輯器. * @author xiao天__ * */ public class SQLEditor extends TextEditor { /**editorID**/ public static String ID = "com.test.SQLEditor"; private ColorManager colorManager; private SQLConfiguration configuration; public SQLEditor() { super(); configuration = new SQLConfiguration(); setSourceViewerConfiguration(configuration); setDocumentProvider(new SQLDocumentProvider()); } /** * 方法說明: 設定字型. */ public void initFont() { FontData fontData = new FontData("Consolas", 11, SWT.NORMAL); Font font = new Font(getEditorSite().getShell().getDisplay(), fontData); this.getSourceViewer().getTextWidget().setFont(font); } public void dispose() { if(colorManager != null) { colorManager.dispose(); } super.dispose(); } @Override public void createPartControl(Composite parent) { super.createPartControl(parent); initFont(); } }
如果大家使用的是有檔案的方式. 就可以直接配置Plug-in.xml檔案方式來開啟SQLEditor, 而小天__使用的是不需要檔案的方式來開啟SQLEditor, 主要是專案需要, 所以這裡給大家寫兩種方式:
方式一:
Plug-in.xml:
<plugin> <extension point="org.eclipse.ui.editors"> <editor name="SQL編輯器" extensions="xml" icon="icons/sample.gif" contributorClass="org.eclipse.ui.texteditor.BasicTextEditorActionContributor" class="com.test.SQLEditor" id="com.test.SQLEditor"> </editor> </extension> </plugin>
方式二:
Plug-in.xml的配置都是一樣的, 因為沒有檔案. 所以我們必須要構建一個Input物件:
SQLEditorInput:
package com.test.editors; import java.io.ByteArrayInputStream; import java.io.InputStream; import org.eclipse.core.resources.IStorage; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.ui.IPersistableElement; import org.eclipse.ui.IStorageEditorInput; import org.eclipse.ui.IViewPart; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; public class SQLEditorInput implements IStorageEditorInput { /**顯示名稱**/ private String name; /**正文**/ private String content = ""; /**儲存器**/ public IStorage storage; public SQLEditorInput(String name) { this.name = name; storage = new IStorage() { @Override public Object getAdapter(Class adapter) { return null; } @Override public boolean isReadOnly() { return isReadOnly; } @Override public String getName() { return SQLEditorInput.this.name; } @Override public IPath getFullPath() { return null; } @Override public InputStream getContents() throws CoreException { return new ByteArrayInputStream(content.getBytes()); } }; } public SQLEditorInput(String name, IStorage is) { this.name = name; this.storage = is; } @Override public boolean exists() { return true; } @Override public ImageDescriptor getImageDescriptor() { return null; } @Override public String getName() { return name; } @Override public IPersistableElement getPersistable() { return null; } @Override public String getToolTipText() { return "SQL編輯器"; } @Override public Object getAdapter(Class adapter) { return null; } @Override public IStorage getStorage() throws CoreException { return storage; } @Override public boolean equals(Object obj) { if(obj instanceof SQLEditorInput){ SQLEditorInput newDbEditorInput = (SQLEditorInput)obj; if(this.name.equals(newDbEditorInput.getName())) { return true; } } return false; } }
開啟編輯器方法:
這個方法可以寫在工具欄的事件裡. 右鍵選單裡. 這個就看需求了.
public void openView() {
SQLEditorInput input = new SQLEditorInput("新建查詢");
try {
page.openEditor(input, "com.test.SQLEditor");
} catch (PartInitException e) {
e.printStackTrace();
}
}
SQLConfiguration類:
package com.zdk.platform.studio.dbassistant.codeassistent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.jface.text.contentassist.IContentAssistant;
import org.eclipse.jface.text.formatter.ContentFormatter;
import org.eclipse.jface.text.formatter.IContentFormatter;
import org.eclipse.jface.text.presentation.IPresentationReconciler;
import org.eclipse.jface.text.presentation.PresentationReconciler;
import org.eclipse.jface.text.rules.DefaultDamagerRepairer;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.SourceViewerConfiguration;
import com.zdk.platform.studio.dbassistant.codeassistent.assistent.SQLContentAssistent;
public class SQLConfiguration extends SourceViewerConfiguration {
private SQLContentAssistent assistent;
public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) {
PresentationReconciler reconciler = new PresentationReconciler();
DefaultDamagerRepairer dr = new DefaultDamagerRepairer(new SQLPartitionScanner());
reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE);
reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE);
return reconciler;
}
@Override
public IContentFormatter getContentFormatter(ISourceViewer sourceViewer) {
ContentFormatter formatter = new ContentFormatter();
formatter.setFormattingStrategy(new SQLFormattingStrategy(), IDocument.DEFAULT_CONTENT_TYPE);
formatter.enablePartitionAwareFormatting(true);
return formatter;
}
/**
* 設定自動提示.
*/
@Override
public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {
ContentAssistant contentAssistent = new ContentAssistant();
assistent = new SQLContentAssistent();
contentAssistent.setContentAssistProcessor(assistent, IDocument.DEFAULT_CONTENT_TYPE);
contentAssistent.enableAutoActivation(true);
contentAssistent.setAutoActivationDelay(200);
return contentAssistent;
}
public DBConfig getDbConfig() {
return dbConfig;
}
}
SQLDocumentProvider類(說實話這個類.小天__都不清楚有什麼用):
package com.zdk.platform.studio.dbassistant.codeassistent;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentPartitioner;
import org.eclipse.jface.text.rules.FastPartitioner;
import org.eclipse.ui.editors.text.FileDocumentProvider;
public class SQLDocumentProvider extends FileDocumentProvider {
protected IDocument createDocument(Object element) throws CoreException {
IDocument document = super.createDocument(element);
if (document != null) {
IDocumentPartitioner partitioner =
new FastPartitioner(
new SQLPartitionScanner(),
new String[] { });
partitioner.connect(document);
document.setDocumentPartitioner(partitioner);
}
return document;
}
}
程式碼高亮部分:
ColorManager類:
package com.zdk.platform.studio.dbassistant.codeassistent;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;
/**
* 類說明: 顏色管理類.
* @author 小天__
*
*/
public class ColorManager {
/**註釋顏色**/
public static final RGB COLOR_COMMENT = new RGB(0, 128, 0);
/**關鍵字顏色**/
public static final RGB COLOR_KEYWORD = new RGB(128, 0, 0);
/**普通文字顏色**/
public static final RGB COLOR_TEXT = new RGB(0, 0, 0);
protected static Map fColorTable = new HashMap(10);
public void dispose() {
Iterator e = fColorTable.values().iterator();
while (e.hasNext())
((Color) e.next()).dispose();
}
public static Color getColor(RGB rgb) {
Color color = (Color) fColorTable.get(rgb);
if (color == null) {
color = new Color(Display.getCurrent(), rgb);
fColorTable.put(rgb, color);
}
return color;
}
}
SQLPartitionScanner:
package com.test.codeassistent;
import org.eclipse.jface.text.TextAttribute;
import org.eclipse.jface.text.rules.EndOfLineRule;
import org.eclipse.jface.text.rules.IPredicateRule;
import org.eclipse.jface.text.rules.RuleBasedPartitionScanner;
import org.eclipse.jface.text.rules.SingleLineRule;
import org.eclipse.jface.text.rules.Token;
import com.test.rule.KeyWordDetector;
import com.test.rule.KeyWordRule;
public class SQLPartitionScanner extends RuleBasedPartitionScanner {
private TextAttribute keywordAttr = new TextAttribute(ColorManager.getColor(ColorManager.COLOR_KEYWORD));
public SQLPartitionScanner() {
IPredicateRule[] rules = new IPredicateRule[1];
rules[0] = new KeyWordRule(new KeyWordDetector(), new Token(keywordAttr));
setPredicateRules(rules);
}
}
KeyWordRule:
package com.zdk.platform.studio.dbassistant.codeassistent.rule;
import org.eclipse.jface.text.rules.ICharacterScanner;
import org.eclipse.jface.text.rules.IPredicateRule;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.IWordDetector;
import org.eclipse.jface.text.rules.Token;
import org.eclipse.jface.text.rules.WordRule;
import com.test.SQLPartitionScanner;
public class KeyWordRule extends WordRule implements IPredicateRule {
private StringBuffer fBuffer= new StringBuffer();
private boolean fIgnoreCase= false;
/**關鍵字**/
public String keywords = "insert,update,delete,select";
public KeyWordRule(IWordDetector detector, IToken defaultToken) {
super(detector, new Token(SQLPartitionScanner.textAttr));
//增加關鍵字
String[] keywordArray = keywords.split(",");
for (int i = 0; i < keywordArray.length; i++) {
String keywrod = keywordArray[i];
addWord(keywrod, defaultToken);
}
}
public IToken evaluate(ICharacterScanner scanner) {
int c= scanner.read();
if (c != ICharacterScanner.EOF && fDetector.isWordStart((char) c)) {
if (fColumn == UNDEFINED || (fColumn == scanner.getColumn() - 1)) {
fBuffer.setLength(0);
do {
fBuffer.append((char) c);
c= scanner.read();
} while (c != ICharacterScanner.EOF && fDetector.isWordPart((char) c));
scanner.unread();
String buffer= fBuffer.toString();
if (fIgnoreCase) {
buffer = buffer.toLowerCase();
}
IToken token= (IToken)fWords.get(buffer);
if (token != null) {
return token;
}
if (fDefaultToken.isUndefined()) {
unreadBuffer(scanner);
}
return fDefaultToken;
}
}
scanner.unread();
return Token.UNDEFINED;
}
@Override
public IToken getSuccessToken() {
return Token.UNDEFINED;
}
@Override
public IToken evaluate(ICharacterScanner scanner, boolean resume) {
return this.fDefaultToken;
}
}
KeyWordDetector:
package com.zdk.platform.studio.dbassistant.codeassistent.rule;
/*******************************************************************************
* Copyright (c) 2000 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* QNX Software System
*******************************************************************************/
import org.eclipse.jface.text.rules.IWordDetector;
/**
* A C aware word detector.
*/
public class KeyWordDetector implements IWordDetector {
/**
* @see IWordDetector#isWordIdentifierStart
*/
public boolean isWordStart(char c) {
if(64 < c && c < 123 || c == '=') { //大寫字母A-Z, 小寫字母a-z;
return true;
}
return false;
}
/**
* @see IWordDetector#isWordIdentifierPart
*/
public boolean isWordPart(char c) {
if(64 < c && c < 123 || c == '=') { //大寫字母A-Z, 小寫字母a-z;
return true;
}
return false;
}
}
程式碼提示部分:
SQLContentAssistent:
package com.test.assistent;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
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;
import com.zdk.platform.studio.pojo.DBConfig;
public class SQLContentAssistent implements IContentAssistProcessor {
/**提示集合**/
public List<IAssistentContent> assistentContentList = new ArrayList<IAssistentContent>();
/**開始位置**/
public int startIndex = 0;
/**當前文件**/
public IDocument doc;
/**資料連線物件**/
private DBConfig dbConfig;
/**
* 構造方法: 新增提示種類.
*/
public SQLContentAssistent() {
super();
assistentContentList.add(new KeywordAssistentData());
}
@Override
public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
this.doc = viewer.getDocument();
List list = new KeywordAssistentData().getAssistentData(this.doc, offset);
return (CompletionProposal[]) list.toArray(new CompletionProposal[list.size()]);
}
@Override
public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
// TODO 自動生成的方法存根
return null;
}
/**
* 設定何時啟用
*/
@Override
public char[] getCompletionProposalAutoActivationCharacters() {
return new char[] {'.'};
}
@Override
public char[] getContextInformationAutoActivationCharacters() {
return null;
}
@Override
public String getErrorMessage() {
// TODO 自動生成的方法存根
return null;
}
@Override
public IContextInformationValidator getContextInformationValidator() {
// TODO 自動生成的方法存根
return null;
}
/**
* 方法說明: 獲取提示前面的字串.
* @param doc
* @param offest
* @return
*/
public String getFrontText(IDocument doc, int offest) {
StringBuffer buf = new StringBuffer();
while(true) { //迴圈新增關鍵字.
try {
char c = doc.getChar(--offest);
startIndex = offest;
if(Character.isWhitespace(c)) {
startIndex++;
break;
}
if(c == ';' || c == '(' || c == ')' || c == '{' || c == '}' || c == ',') { //結束符號.
startIndex++;
break;
}
buf.append(c);
} catch (BadLocationException e) {
break;
}
}
return buf.reverse().toString();
}
}
KeywordAssistentData:
package com.test.assistent;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.CompletionProposal;
import com.zdk.platform.studio.dbassistant.codeassistent.Contents;
/**
* 類說明: 關鍵字提示資料類.
* @author Administrator
*
*/
public class KeywordAssistentData implements IAssistentContent {
private int start = 0;
@Override
public List<CompletionProposal> getAssistentData(IDocument doc, int offset) {
String str = getFrontText(doc, offset);
List<CompletionProposal> list = new ArrayList<CompletionProposal>();
//用正則匹配.
Pattern p = null;
Matcher m = null;
for (int i = 0; i < Contents.KEY_WORD_ARRAY.length; i++) {
String keyWord = Contents.KEY_WORD_ARRAY[i];
p = Pattern.compile("(^" + str + ")", Pattern.CASE_INSENSITIVE);
m = p.matcher(keyWord);
if(m.find()) {
String insert = Contents.KEY_WORD_ARRAY[i];
//建立替換類容. insert:替換文字, offset:替換其實位置.
//0:替換結束位置.偏移量, insert.length:替換完成後.游標位置偏移量.
CompletionProposal proposal = new CompletionProposal(insert, start, offset - start, insert.length());
list.add(proposal);
}
}
return list;
}
/**
* 方法說明: 獲取提示前面的字串.
* @param doc
* @param offest
* @return
*/
public String getFrontText(IDocument doc, int offest) {
StringBuffer buf = new StringBuffer();
while(true) { //迴圈新增關鍵字.
try {
char c = doc.getChar(--offest);
start = offest;
if(Character.isWhitespace(c)) {
start++;
break;
}
if(c == ';' || c == '(' || c == ')' || c == '{' || c == '}' || c == ',') { //結束符號.
start++;
break;
}
buf.append(c);
} catch (BadLocationException e) {
break;
}
}
return buf.reverse().toString();
}
}
以上就是大部分程式碼了.