·1 目的
無論是Visual stuio還是Eclipse等衆多IDE,映入我們眼簾最直觀的就是各種語法着色,關鍵字如“int”,字符串如"ddd",註釋如“com.bbe”。
今天我們學習如何讓你的編輯器支持語法着色。
·2 定義
我們首先從思想上定義哪些輸入串將被語法着色,以及它們的顏色和字體類型,我們有如下三種模式將被語法着色:
Ø 關鍵字
關鍵字包括SELECT, FROM和WHERE
n 顏色:RGB(127, 0, 85)
n style:SWT.BOLD
n 示例:CREATE
Ø 字符串
n 顏色:RGB(42, 0, 255)
n style:默認
n 示例:"String"
Ø 註釋
n 顏色:RGB(63, 95, 191)
n style:默認
n 示例:/*Zero Bobo Resource Manager */
是的,正如你所見,我們使用的是Eclipse的默認語法顏色。
·3 分析
·3.1 如何讓編輯器着色
想想,怎麼才能讓編輯器語法着色?
Ø 我們必須有一個語法(詞法)掃描器(Scanner),它能夠分解出輸入中的單詞(Token),並且根據某種模式判斷出單詞的類型,是關鍵字、字符串還是數字?在此前我們已經定義了各種Token類型對應的語法顏色和字體類型(如·2定義中描述)。
Ø AbstractDecoratedTextEditor上有一個SourceViewer。SourceViewer屬於JFace,它封裝了StyledText。我們還必須爲SourceViewer設置一個Configuration以支持對SourceViewer提供各種增加功能(add-ons),由它支持對SourceViewer進行語法着色。
·3.2 Eclipse的策略
針對我們上面的考慮,Eclipse中有對應的類實現它們:
● org.eclipse.jface.text.rules.RuleBasedScanner類
爲了支持語法着色功能,就必須使用某種掃描器對輸入進行語法分析,將輸入分解爲一個個的記號(Token),同時還要確定這些Token屬於什麼類型,是關鍵字還是字符串。
定位於org.eclipse.jface.text.rules下的RuleBasedScanner類提供了掃描器的功能,該類可設置多個Rule(規則),對於輸入按序執行這些rule,當某個Rule能夠成功evaluate一個輸入,就返回一個定義好的Token。如果一個rule返回了一個UN_DEFINE的TOKEN,就繼續讓下一個Rule來解析。如果沒有Rule能夠返回定義的token,則Scanner返回一個特定的Token,對該token調用isOther()將返回true。如果遇到了文件的結尾,則對Scanner返回的Token調用isEOF返回true。
我們自己定義一個ZSqlScanner類繼承RuleBasedScanner,並在構造中設置需要的rule。
關於Rule主要有如下幾種(Rule均實現IRule接口):
a) WordRule實現IRule:該規則可以發現一個完整的字,比如Java或SQL的關鍵字,他們的語法組成是固定的,int就是int,long就是long,通過這個規則可以發現這些關鍵字。WordRule需要一個IWordDetector接口的實例來輔助分析(實際上WordRule有點小問題,在後面介紹)。
b) WhitespaceRule實現IRule:顧名思義,發現輸入中的空白字符。WhitespaceRule需要一個IWhitespaceDetector接口的實例來輔助分析。
c) SingleLineRule繼承PatternRule:根據某種模式匹配規則,比如字符串由“””開始和結束。但SingleLineRule要求字符序列必須在單行上匹配模式。
d) MultiLineRule與SingleLineRule類似,不同在於MultiLineRule允許字符序列在多行上匹配模式(比如多行註釋/* */可用這種規則)。
e) EndOfLineRule繼承自SingleLineRule,它開始於某種指定的模式,結束一定是一個換行符(line delimiter),比如單行註釋“//abcd”就可使用這種規則。
● org.eclipse.jface.text.source.SourceViewerConfiguration類
在前言中我們已經瞭解,SourceViewer通過SourceViewerConfiguration類來控制其各種增件配置,如代碼着色,自動提示等。爲了支持語法着色,我們必須提供自己的SourceViewerConfiguration類:ZSqlSourceViewerConfiguration,並且重寫getPresentationReconciler方法。
IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer)方法,返回一個IPresentationReconciler接口的實例,該實例上註冊了了一個毀壞器(damager)和一個修復器(repairer)。
damager負責計算文檔被修改的區域
repairer負責重新構建文檔被修改區域的表現形式(着色)
·4 源代碼
通過分析,我們的思想已經有了,下面就來看源代碼。由於篇幅關係,我們不在這裏介紹所有的源代碼,只介紹增加的和重要的代碼。介紹的順序按照執行的流程。
·4.1 擴展父類的initializeEditor()方法,並如下實現:
super.initializeEditor();
this.setSourceViewerConfiguration(new
ZSqlSourceViewerConfiguration());
initializeEditor()方法會在ZSqlEditor的構造方法前執行,因爲在AbstractDecoratedTextEditor類的構造中調用了initializeEditor()方法,此時ZSqlEditor的構造方法還沒有執行(請參考我的另一篇文章,Java對象的構造順序-讓代碼在構造方法前執行)。
你也許會問,此時我們的SourceViewer還沒有創建,怎麼能夠設置Configuration,實際上AbstractTextEditor會爲你保持Configuration對象,並在其createPartControl()方法中將其配置到SourceViewer上。ZSqlEditor.intializeEditor()在ZSqlEditor的構造方法之前執行(因爲它在父類AbstractDecoratedTextEditor的構造方法中被調用)因此我們在這裏設置Configuration。而在AbstractTextEditor.createPartControl()方法中,將調用createSourceViewer()方法創建SourceViewer的實例,併爲SourceViewer配置Configuration(使用我們設置的configuration)。而一旦爲SourceViewer設置了Configuration,就不能重新配置,否則會出現IllegalStateException異常(因此,你實際上可以在ZSqlEditor的initializeEditor(), constructor(), init()方法,包括createPartControl()方法(調用super.createPartControl()方法之前)調用setSourceViewerConfiguration()方法)。
·4.2 增加類ZSqlSourceViewerConfiguration
extends SourceViewerConfiguration
重寫public IPresentationReconciler getPresentationReconciler(
ISourceViewer sourceViewer)方法
·4.3 增加類ZSqlScanner extends RuleBasedScanner
·4.4 增加類ZSqlWhiteSpaceDetector, ZSqlWordDetector
這兩個類均爲Rule的輔助類,負責發現空白字符和關鍵字。
·4.5 增加接口ZISqlSyntax
這個接口用來提供各種字符串數組,當前僅提供關鍵字字符串數組。ZSqlWordDetector根據這些來判斷某個模式是否關鍵字。
·5 運行
點擊下載(http://www.sinadisk.com/pick.aspx?code=com.bbebfe.sql_source_highlight)源代碼工程和插件Jar包。
下載完成後你可以選擇導入源代碼工程或者直接將Jar包拷貝到Eclipse的plugins目錄下。通過File -> open file打開任意.sql後綴就可以激活編輯器。運行效果如下:
·6 總結
在本章我們學習瞭如何讓我們的編輯器支持語法着色,雖然我們只定義了最簡單的幾種模式,但你完全可以以此推導出其他的多種模式。不過目前編輯器在代碼着色方面仍然有些小問題,將在下一章介紹並解決。
·7 參考文獻
[美]Jim D’Anjou等,《Eclipse權威開發指南》,清華大學出版社
Eclipse示例:org.eclipse.ui.examples.javaeditor