用c#实现的语法高亮控件

因为工作需要,用c#实现了一个能够对vbscript,c#,j#,sql显示语法高亮的文本编辑控件。这里详细介绍一下它的原理。

该控件是从RichTextBox继承下来,以xml格式存储各种语言的关键字。然后重写RichTextBox的OnTextChanged方法,在该方法中对输入文本进行解析,并对关键字进行着色。源代码点击 这里 下载。

xml文件格式如下,这里仅以j#为例。caseSensitive代表该语言是否大小写敏感。当然,由于本人懒惰成性,关键字是从网上搜集别人整理好的,如有遗漏,概不负责:)

如果需要解析其他语言,请添加相应的xml文件,并修改枚举类型Languages以及Parser类的构造函数中的相应代码。已知bug:当两个词是由括号分割的时候,程序无法识别。比如Function foo(integer i),程序会把foo(integer当作一个词。当然这里有两个解决办法,一个是程序自动进行语法排版,在括号前后自动插入空格;另一个是对括号进行解析。也许以后有空的时候我会加上。

 1<definition casesensitive="true" name="J#">
 2<word>private</word>
 3<word>protected</word>
 4<word>public</word>
 5<word>namespace</word>
 6<word>class</word>
 7<word>var</word>
 8<word>for</word>
 9<word>if</word>
10<word>else</word>
11<word>while</word>
12<word>switch</word>
13<word>case</word>
14<word>using</word>
15<word>get</word>
16<word>return</word>
17<word>null</word>
18<word>void</word>
19<word>int</word>
20<word>string</word>
21<word>float</word>
22<word>this</word>
23<word>set</word>
24<word>new</word>
25<word>true</word>
26<word>false</word>
27<word>const</word>
28<word>static</word>
29<word>package</word>
30<word>function,</word>
31<word>internal</word>
32<word>extends</word>
33<word>super</word>
34<word>import</word>
35<word>default</word>
36<word>break</word>
37<word>try</word>
38<word>catch</word>
39<word>finally</word>
40<word>+</word>
41<word>-</word>
42<word>=</word>
43</definition>

Parser类是负责对xml流进行解析,并包含一个方法来判断一个字符串是不是关键字。详细的代码和注释如下:

using System;
using System.Xml;
using System.IO;
using System.Collections;
using System.Reflection;

namespace SyntaxEditor
{
///

1<summary>   
2/// Parser 的摘要说明。   
3/// </summary>

public class Parser
{
private XmlDocument xd=null;
private ArrayList al=null; //对xml流解析后,会把每一个关键字字符串放入这个容器中
private bool caseSensitive=false; //记录当前语言大小写敏感否

internal Parser(SyntaxEditor.Languages language) //构造函数接受一个枚举变量
{
//
// TODO: 在此处添加构造函数逻辑
//

Assembly asm = Assembly.GetExecutingAssembly();
string filename="";
switch(language) //取得xml文件名
{
case SyntaxEditor.Languages.CSHARP:
filename="csharp.xml";
break;
case SyntaxEditor.Languages.JSHARP:
filename="jsharp.xml";
break;
case SyntaxEditor.Languages.SQL:
filename="sql.xml";
break;
case SyntaxEditor.Languages.VBSCRIPT:
filename="vbscript.xml";
break;
default:
break;
}

Stream strm = asm.GetManifestResourceStream(asm.GetName().Name + "."+filename); //取得xml流

//Reads the contents of the embedded file.
StreamReader reader= new StreamReader(strm); //下面的代码解析xml流

xd=new XmlDocument();
xd.Load(reader);

al=new ArrayList();

XmlElement root=xd.DocumentElement;

XmlNodeList xnl=root.SelectNodes("/definition/word");
for(int i=0;i

  1<xnl.count;i++) <summary="" al.add(xnl[i].childnodes[0].value);="" bool="" break;="" for(int="" hwnd="System.IntPtr;" i="0;i&lt;al.Count;i++)" if(string.compare(word,al[i].tostring(),!casesensitive)="0)" iskeyword(string="" namespace="" public="" return="" rtn="true;" rtn;="" syntaxeditor="" system.collections;="" system.componentmodel;="" system.data;="" system.drawing;="" system.runtime.interopservices;="" system.windows.forms;="" system;="" this.casesensitive='bool.Parse(root.Attributes["caseSensitive"].Value);' using="" word)="" {="" }="" 判断字符串是否为关键字="" 控件类代码如下。="">   
  2/// UserControl1 的摘要说明。   
  3///    
  4public class SyntaxEditor : System.Windows.Forms.RichTextBox   
  5{   
  6/// <summary>   
  7/// 必需的设计器变量。   
  8/// </summary>   
  9private System.ComponentModel.Container components = null; 
 10
 11//使用win32api: **SendMessage** 来防止控件着色时的闪烁现象 
 12
 13**[DllImport("user32")] private static extern int SendMessage(HWND hwnd, int wMsg, int wParam, IntPtr lParam);  
 14** private const int WM_SETREDRAW = 0xB; 
 15
 16public SyntaxEditor()   
 17{   
 18// 该调用是 Windows.Forms 窗体设计器所必需的。   
 19InitializeComponent();   
 20base.WordWrap=false;   
 21// TODO: 在 InitComponent 调用后添加任何初始化 
 22
 23} 
 24
 25/// <summary>   
 26/// 清理所有正在使用的资源。   
 27/// </summary>   
 28protected override void Dispose( bool disposing )   
 29{   
 30if( disposing )   
 31{   
 32if( components != null )   
 33components.Dispose();   
 34}   
 35base.Dispose( disposing );   
 36} 
 37
 38#region 组件设计器生成的代码   
 39/// <summary>   
 40/// 设计器支持所需的方法 - 不要使用代码编辑器   
 41/// 修改此方法的内容。   
 42/// </summary>   
 43private void InitializeComponent()   
 44{   
 45//   
 46// SyntaxEditor   
 47//   
 48this.Name = "SyntaxEditor"; 
 49
 50}   
 51#endregion 
 52
 53**//重写基类的OnTextChanged方法。为了提高效率,程序是对当前文本插入点所在行进行扫描,**
 54
 55**//以空格为分割符,判断每个单词是否为关键字,并进行着色。**
 56
 57**protected override void OnTextChanged(EventArgs e)  
 58{   
 59if(base.Text!="")   
 60{   
 61int selectStart=base.SelectionStart;   
 62int line=base.GetLineFromCharIndex(selectStart); **
 63
 64**string lineStr=base.Lines[line];  
 65int linestart=0;   
 66for(int i=0;i&lt;line;i++)   
 67{   
 68linestart+=base.Lines[i].Length+1;   
 69}   
 70  
 71SendMessage(base.Handle, WM_SETREDRAW, 0, IntPtr.Zero); **
 72
 73**base.SelectionStart=linestart;  
 74base.SelectionLength=lineStr.Length;   
 75base.SelectionColor=Color.Black;   
 76base.SelectionStart=selectStart;   
 77base.SelectionLength=0; **
 78
 79**string[] words=lineStr.Split(new char[]{' '});  
 80Parser parser=new Parser(this.language);   
 81for(int i=0;i&lt;words.Length;i++)   
 82{   
 83if(parser.IsKeyWord(words[i]))   
 84{   
 85  
 86int length=0;   
 87for(int j=0;j&lt;i;j++)   
 88{   
 89length+=words[j].Length;   
 90}   
 91length+=i; **
 92
 93**int index=lineStr.IndexOf(words[i],length);  
 94  
 95**
 96
 97**base.SelectionStart=linestart+index;  
 98base.SelectionLength=words[i].Length;   
 99base.SelectionColor=Color.Blue;   
100base.SelectionStart=selectStart;   
101base.SelectionLength=0;   
102base.SelectionColor=Color.Black; **
103
104**}  
105}   
106SendMessage(base.Handle, WM_SETREDRAW, 1, IntPtr.Zero);   
107base.Refresh();   
108}   
109base.OnTextChanged (e);   
110} **
111
112public new bool WordWrap   
113{   
114get{return base.WordWrap;}   
115} 
116
117public enum Languages   
118{   
119SQL,   
120VBSCRIPT,   
121CSHARP,   
122JSHARP   
123}   
124  
125private Languages language=Languages.SQL; 
126
127public Languages Language   
128{   
129get{return this.language;}   
130set{this.language=value;}   
131}   
132}   
133}</xnl.count;i++)>
Published At
Categories with Web编程
Tagged with
comments powered by Disqus