最近在开发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; } }
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); } }
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; } }
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(); } }
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(); } }
以上就是大部分代码了.