这是
GacUI关于文本框高亮的最后一个Demo了。这个Demo是关于XML着色的。XML着色比起C++着色更难,主要是因为在类似<book name="C++ Primer">这样的代码里面,book和name的颜色不一样,<和book的颜色也不一样(参考Visual Studio)。这种时候单纯依靠正则表达式来区分颜色是不够的,我们还需要引入一个新的状态机。这个状态机只有三个状态,用来区分tag name,attribute name和text三种颜色。状态机是手写的,并且GacUI提供了一个回调来写这个只有寥寥几行状态机。先看图:
跟C++一样,XML着色首先是由正则表达式组成的。XML的正则表达式比较简单,只有符号、name、字符串、CData、注释和其它一些简单的东西:
1 class XmlColorizer : public GuiTextBoxRegexColorizer
2 {
3 public:
4 XmlColorizer()
5 {
6 text::ColorEntry entry=win7::Win7GetTextBoxTextColor();
7 SetDefaultColor(entry);
8
9 entry.normal.text=Color(0, 128, 0);
10 AddToken(L"/<!--([^/-]|-[^/-]|--[^>])*--/>", entry);
11
12 entry.normal.text=Color(128, 0, 255);
13 AddToken(L"/<!/[CDATA/[([^/]]|/][^/]]|/]/][^>])*/]/]/>", entry);
14
15 entry.normal.text=Color(0, 0, 0);
16 AddToken(L"\"[^\"]*\"", entry);
17
18 entry.normal.text=Color(0, 0, 255);
19 AddToken(L"[<>=]", entry);
20
21 entry.normal.text=Color(255, 0, 0);
22 AddToken(L"[a-zA-Z0-9_/-:]+", entry);
23
24 entry.normal.text=Color(163, 21, 21);
25 AddExtraToken(entry);
26
27 Setup();
28 }
29
30 void ColorizeTokenContextSensitive(const wchar_t* text, vint start, vint length, vint& token, int& contextState)override
31 {
32
33 }
34
35 int GetContextStartState()override
36 {
37
38 }
39 }; 其次要对三种地方的[a-zA-Z0-9_/-:]进行着色。Tag的名字用褐色,attribute的名字用红色,而普通文本用黑色。因此我们可以做一个状态机,初始状态为0。如果读进了<,状态变成1。1遇到了一个Tag名字之后变为2。从2开始所有的名字就只能是attribute的名字了。我们只考虑正确的情况,错误的代码着色出了问题不仅没有坏处,还可以提醒程序员有什么地方写错了。之后遇到了>变回0,在0的状态下所有的东西都是普通文本,所以名字就都是黑色的。因此上面ColorizeTokenContextSensitive函数中就需要填入这个逻辑。GetContextStartState返回0,作为第一行的起始状态。代码如下:
void ColorizeTokenContextSensitive(const wchar_t* text, vint start, vint length, vint& token, int& contextState)override
{
// 0 < 1 name 2 att > 0
switch(token)
{
case 3:
if(length==1)
{
switch(text[start])
{
case '<':
contextState=1;
break;
case '>':
contextState=0;
break;
}
}
break;
case 4:
switch(contextState)
{
case 0:
token=-1;
break;
case 1:
token=5;
contextState=2;
break;
}
break;
}
}
int GetContextStartState()override
{
return 0;
}
这个函数里面有几个魔法数字,其实都是关于Token的编号的。构造函数里面我们使用AddToken将一个颜色关联到正则表达式上,使用AddExtraToken创建一个没有正则表达式关联的颜色。所以在这个状态机里面,所有的颜色都用Token的序号来表示。无论是使用AddToken还是AddExtraToken,第一个颜色编号为0,第二个颜色编号为1。因此case 3指的是[<>=],而case 4指的是[a-zA-Z0-9_/-:]+。而case 4里面的token=5则表示在状态为1的时候,名字都用AddExtraToken指定的那个褐色进行染色。缺省的名字(也就是id为4的token)是红色,所以不需要对contextState为2的时候进行处理。
这样我们就完成了XML的着色。GacUI接下来的几个Demo将会是关于ListBox、ListView和TreeView的,敬请期待。
posted on 2012-05-20 00:41
陈梓瀚(vczh) 阅读(2233)
评论(2) 编辑 收藏 引用 所属分类:
GacUI