C# writing a code editor issues
So I'm writing a simple code editor for a language I like. I have syntax hilighting going very well. The problem is that if I go back before text I have already written, it screws the whole hilighting up for everything past my pointer. Here is my code, my apologies for posting so much:
public partial class Form1 : Form
{
public string MainFontName = "Courier New";
public int MainFontSize = 12;
public Color MainFontColor = Color.Black;
[DllImport("user32.dll")] // import lockwindow to remove flashing
public static extern bool LockWindowUpdate(IntPtr hWndLock);
public Regex codeFunctions = new Regex("draw_line|draw_rectangle|draw_circle");
public Regex codeKeywords = new Regex("and|for|while|repeat|or|xor|exit|break|case|switch|if|then|with|true|false");
public Form1()
{
InitializeComponent();
CodeInput.Font = new Font(MainFontName, MainFontSize, FontStyle.Regular);
}
private void CodeInput_TextChanged(object sender, EventArgs e)
{
开发者_运维问答 CodeInput.Font = new Font(MainFontName, MainFontSize, FontStyle.Regular);
try
{
LockWindowUpdate(CodeInput.Handle);
int selPos = CodeInput.SelectionStart;
CodeInput.Select(0, CodeInput.TextLength);
CodeInput.SelectionFont = new Font(MainFontName, MainFontSize, FontStyle.Regular);
CodeInput.SelectionColor = Color.Black;
CodeInput.SelectionLength = 0;
CodeInput.SelectionStart = selPos;
//Match the functions
foreach (Match keyWordMatch in codeFunctions.Matches(CodeInput.Text))
{
CodeInput.Select(keyWordMatch.Index, keyWordMatch.Length);
CodeInput.SelectionColor = Color.Red;
CodeInput.SelectionStart = selPos;
CodeInput.SelectionColor = MainFontColor;
CodeInput.SelectionLength = 0;
}
// Match the keywords
foreach (Match keyWordMatch in codeKeywords.Matches(CodeInput.Text))
{
Font oFont = new Font(MainFontName, MainFontSize, FontStyle.Bold);
Font nFont = new Font(MainFontName, MainFontSize, FontStyle.Regular);
CodeInput.Select(keyWordMatch.Index, keyWordMatch.Length);
CodeInput.SelectionColor = Color.Blue;
CodeInput.SelectionFont = oFont;
CodeInput.SelectionStart = selPos;
CodeInput.SelectionColor = MainFontColor;
CodeInput.SelectionFont = nFont;
CodeInput.SelectionLength = 0;
}
}
finally
{
LockWindowUpdate(IntPtr.Zero);
}
}
}
Thanks for the help.
You are almost on the right track but try blocking WM_PAINT instead of using API calls,i have worked on this type of project and implemented syntax highlighting successfully,its original source code is as below;
///RadonCodeEditor is the name of Project
/// <summary>
/// Gets or sets a value whether RadonTextEditor should repaint itself.
/// </summary>
public bool Repaint = true;
cKeyword=Color.Blue;
cComment=Color.Green;
/// <summary>
/// A Windows generated message send to a control that needs repainting.
/// </summary>
const short WM_PAINT = 0x00f;
/// <summary>
/// Contains creation data to call RadonTextEditor.
/// </summary>
public RadonTextEditor()
{
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);//Reduces flickering.
}
/// <summary>
/// Overrides default WndProc and handles WM_PAINT message to remove flickering.
/// </summary>
/// <param name="m">The message in message queue.</param>
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_PAINT)//If the message in the message queue is WM_PAINT.
{
switch (Repaint)
{
case true://When we want RadonTextEditor to repaint.
base.WndProc(ref m);
break;
case false://When we don't want RadonTextEditor to repaint.
m.Result = IntPtr.Zero;
break;
}
}
else//If the message in the message queue is anything else but not WM_PAINT.
{
base.WndProc(ref m);
}
}
//Import namespace System.Text.RegularExpressions
/// <summary>
/// Checks the input text for any contained comments using a defined Regular Expression.
/// </summary>
/// <param name="Text">The text to check.</param>
/// <param name="FirstCharIndex">The first character index of current line.</param>
/// <param name="CaretPosition">The position of caret.</param>
/// <param name="rtb">The handle to RichTextBox for highlighting.</param>
/// <returns>If the input text contains any text the return value is true otherwise false.</returns>
public void IsComment(string Text, int FirstCharIndex, int CaretPosition, RichTextBox rtb)
{
rComment = new Regex(@"\/\/.*$", RegexOptions.Compiled);
MatchCollection Matches = rComment.Matches(Text);
foreach (Match match in Matches)
{
rtb.Select(match.Index + FirstCharIndex, match.Length);
rtb.SelectionColor = cComment;
rtb.DeselectAll();
rtb.SelectionStart = CaretPosition;
}
rMultiComment = new Regex(@"/\*.*?\*/", RegexOptions.Multiline);
MatchCollection Matches2 = rMultiComment.Matches(Text);
foreach (Match match2 in Matches2)
{
rtb.Select(match2.Index + FirstCharIndex, match2.Length);
rtb.SelectionColor = cComment;
rtb.DeselectAll();
rtb.SelectionStart = CaretPosition;
}
}
/// <summary>
/// Checks the input text for any contained keywords using a defined Regular Expression.
/// </summary>
/// <param name="Text">The text to check.</param>
/// <param name="FirstCharIndex">The first character index of current line.</param>
/// <param name="CaretPosition">The position of caret.</param>
/// <param name="rtb">The handle to RichTextBox for highlighting.</param>
/// <returns>If the input text contains any text the return value is true otherwise false.</returns>
public void IsKeyword(string Text, int FirstCharIndex, int CaretPosition, RichTextBox rtb)
{
rKeyword = new Regex(@:\bint\b|\bdouble\b|\bstring\b", RegexOptions.Compiled);
MatchCollection Matches = rKeyword.Matches(Text);
foreach (Match match in Matches)
{
rtb.Select(match.Index + FirstCharIndex, match.Length);
rtb.SelectionColor = cKeyword;
rtb.DeselectAll();
rtb.SelectionStart = CaretPosition;
}
}
That's it,call both functions in TextChange event handler and pass required arguments to functions as described by comments(I know it's a bit messy because i have directly pasted the source code from the project that i have.)If still anything goes wrong i'll be glad to help you.
精彩评论