GacUI Demo:文本框高亮(三,完)上下文相关着色

GacUI Demo:文本框高亮(三,完)上下文相关着色
    这是 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的,敬请期待。

你可能感兴趣的:(GacUI Demo:文本框高亮(三,完)上下文相关着色)