代码中自动缩进括号的算法

时间:2013-05-08 05:00:09

标签: c# winforms auto-indent

我正在使用代码编辑器(WinForms),我想知道如何使用括号(打开和关闭)来实现{和}的自动缩进功能,就像在实际的代码编辑器中一样。

  

--- |> {和}

像这样1:

enter image description here

编辑器是一个名为rtb的富文本框。

2 个答案:

答案 0 :(得分:4)

好吧,我的解决方案是错误的,但它足以让你了解它是如何工作的

我的结果:

{
        {
                {
                        }
                }
        }

这里是我的代码

public partial class Form1 : Form
{
    private bool FLAG_Selftimer = false;
    private bool FLAG_KeyPressed = false;
    private int pos = 0;
    public Form1()
    {
        InitializeComponent();
    }

    private void richTextBox1_TextChanged(object sender, EventArgs e)
    {
        var rtb = sender as RichTextBox;
        var point = rtb.SelectionStart;

        if (!FLAG_Selftimer)
        {
            rtb.Text = ReGenerateRTBText(rtb.Text);
            FLAG_KeyPressed = false;
        }
        else
        {
            point ++;
            FLAG_Selftimer = false;
        }

        rtb.SelectionStart = point;
    }



    private string ReGenerateRTBText(string Text)
    {
        string[] text = Regex.Split(Text,"\n");

        int lvl = 0;
        string newString = "";
        foreach (string line in text)
        {
            line.TrimStart(' ');
            newString += indentation(lvl) + line.TrimStart(' ') + "\n";
            if (line.Contains("{"))
                lvl++;
            if (line.Contains("}"))
                lvl--;
        }

        FLAG_Selftimer = true;
        return (!FLAG_KeyPressed) ? newString : newString.TrimEnd('\n');
    }

    private string indentation(int IndentLevel)
    {
        string space = "";
        if(IndentLevel>0)
            for (int lvl = 0; lvl < IndentLevel; lvl++)
            {
                    space += " ".PadLeft(8);
            }

        return space;
    }

    private void richTextBox1_KeyPress(object sender, KeyPressEventArgs e)
    {
        FLAG_KeyPressed = true;
    }
}

我希望这会对你有所帮助

答案 1 :(得分:1)

请在阅读和使用代码前阅读以下文字:

  1. 我没有足够的时间来编写更好的代码。我只是试图为你写样本
  2. 我只是以简单的方式编写代码,不在OOP中
  3. 您可以使用枚举属性 OOP的其他内容
  4. 您可以改善代码的逻辑;并且您可以使用多线程来实现更好的性能
  5. 此示例不彻底。我只为“分号(;)”字符实现了自动缩进示例。
  6. 我应该说一些提示来使用这些代码:

    1. rtbCodes 是示例项目中表单上的RichTextBox控件的名称
    2. frmCodeEditor 是示例项目中表单名称。
    3. 您可以从以下地址下载示例项目:

      4Shared -> Auto-Indention for Code Editor

      SendSpace -> Auto-Indention for Code Editor

      using System;
      using System.Collections.Generic;
      using System.ComponentModel;
      using System.Data;
      using System.Diagnostics;
      using System.Drawing;
      using System.Linq;
      using System.Text;
      using System.Windows.Forms;
      
      namespace WindowsFormsApplication2
      {
          public partial class frmCodeEditor : Form
          {
              char[] chrTracingKeyChars = new char[] { ';', '}', '\n' };
              char[] chrCheckingKeyChars = new char[] { '{', '(' };
              Point ptCurrentCharPosition;
              bool bolCheckCalling = false;
              int intInitialCursorPosition = 0;
              int intRemainingCharsOfInitialText = 0;
              int intNextCharIndex = 0;
              int intPrevCharIndex = 0;
      
              public frmCodeEditor()
              {
                  InitializeComponent();
              }
      
              private void richTextBox1_TextChanged(object sender, EventArgs e)
              {
                  AutoIndention(rtbCodes);
              }
      
              /// <summary>
              /// Implements Auto-Indention.
              /// </summary>
              /// <param name="rtb">A RichTextBox control</param>
              private void AutoIndention(RichTextBox rtb)
              {
                  char chrLastChar = GetChar(rtb);
      
                  if (chrLastChar == chrTracingKeyChars[0])
                  {
                      intRemainingCharsOfInitialText = rtb.TextLength - rtb.SelectionStart;
                      intInitialCursorPosition = rtb.SelectionStart;
                      ImplementIndentionForSemicolon(rtb);
                  }
                  else if (chrLastChar == chrTracingKeyChars[1])
                  {
                      ImplementIndentionForRightCurlyBracket(rtb);
                  }
                  else if (chrLastChar == chrTracingKeyChars[2])
                  {
                      ImplementIndentionForNewLineCharacter(rtb);
                  }
              }
      
              /// <summary>
              /// Specifies current char based on the cursor position.
              /// </summary>
              /// <param name="rtb">A RichTextBox control</param>
              /// <returns>Returns a char.</returns>
              private char GetChar(RichTextBox rtb)
              {
                  return GetChar(rtb.SelectionStart, rtb);
              }
      
              /// <summary>
              /// Specifies a char based on the specified index.
              /// </summary>
              /// <param name="intCharIndex">A char index</param>
              /// <param name="rtb">A RichTextBox control</param>
              /// <returns>Returns a char.</returns>
              private char GetChar(int intCharIndex, RichTextBox rtb)
              {
                  if (intCharIndex != rtb.TextLength)
                  {
                      ptCurrentCharPosition = rtb.GetPositionFromCharIndex(intCharIndex - 1);
                  }
                  else
                  {
                      ptCurrentCharPosition = rtb.GetPositionFromCharIndex(intCharIndex);
                  }
                  return rtb.GetCharFromPosition(ptCurrentCharPosition);
              }
      
              /// <summary>
              /// Specifies current line number based on the cursor position.
              /// </summary>
              /// <param name="rtb">A RichTextBox control</param>
              /// <returns>Returns the line number.</returns>
              private int GetLineNumber(RichTextBox rtb)
              {
                  return GetLineNumber(rtb.GetFirstCharIndexOfCurrentLine(), rtb);
              }
      
              /// <summary>
              /// Specifies the line number based on the specified index.
              /// </summary>
              /// <param name="intCharIndex">A char index</param>
              /// <param name="rtb">A RichTextBox control</param>
              /// <returns>Returns the line number.</returns>
              private int GetLineNumber(int intCharIndex, RichTextBox rtb)
              {
                  return rtb.GetLineFromCharIndex(intCharIndex);
              }
      
              /// <summary>
              /// Implements indention for semicolon ";" character.
              /// </summary>
              /// <param name="rtb">A RichTextBox control</param>
              private void ImplementIndentionForSemicolon(RichTextBox rtb)
              {
                  Dictionary<char, int> dicResult = IsExistCheckingKeyChars(rtb);
                  if (dicResult[chrCheckingKeyChars[0]] != -1)
                  {
                      int intIndentionLevel = CheckingIndentionLevel(dicResult[chrCheckingKeyChars[0]], rtb);
                      ImplementIndention(dicResult[chrCheckingKeyChars[0]], intIndentionLevel, rtb);
                  }
              }
      
              private void ImplementIndentionForRightCurlyBracket(RichTextBox rtb)
              {
      
              }
      
              private void ImplementIndentionForNewLineCharacter(RichTextBox rtb)
              {
      
              }
      
              /// <summary>
              /// Checks current and previous lines for finding key-chars.
              /// </summary>
              /// <param name="rtb">A RichTextBox control</param>
              /// <param name="bolSearchCurrentLine">The search state</param>
              /// <returns>Returns first occurrences of key-chars before current char.</returns>
              private Dictionary<char, int> IsExistCheckingKeyChars(RichTextBox rtb, bool bolSearchCurrentLine = false)
              {
                  GetChar(rtb);
      
                  Dictionary<char, int> dicCheckingKeyCharsIndexes = new Dictionary<char, int>();
                  for (int intCntr = 0; intCntr < chrCheckingKeyChars.Length; intCntr++)
                  {
                      dicCheckingKeyCharsIndexes.Add(chrCheckingKeyChars[intCntr], 0);
                  }
      
                  for (int intCntr = 0; intCntr < chrCheckingKeyChars.Length; intCntr++)
                  {
                      int intFirstIndexForChecking = 0;
                      int intLastIndexForChecking = 0;
                      for (int intLineCounter = GetLineNumber(rtb); intLineCounter >= 0; intLineCounter--)
                      {
                          if (intLineCounter == GetLineNumber(rtb))
                          {
                              intLastIndexForChecking = rtb.GetCharIndexFromPosition(ptCurrentCharPosition);
                          }
                          else
                          {
                              intLastIndexForChecking = intFirstIndexForChecking - 1;
                          }
                          intFirstIndexForChecking = rtb.GetFirstCharIndexFromLine(intLineCounter);
      
                          try
                          {
                              dicCheckingKeyCharsIndexes[chrCheckingKeyChars[intCntr]] = rtb.Find(chrCheckingKeyChars[intCntr].ToString(), intFirstIndexForChecking,
                                  rtb.GetCharIndexFromPosition(ptCurrentCharPosition), RichTextBoxFinds.NoHighlight | RichTextBoxFinds.None);
                              if (dicCheckingKeyCharsIndexes[chrCheckingKeyChars[intCntr]] != -1)
                              {
                                  do
                                  {
                                      if (rtb.Find(chrCheckingKeyChars[intCntr].ToString(), intFirstIndexForChecking, rtb.GetCharIndexFromPosition(ptCurrentCharPosition),
                                          RichTextBoxFinds.NoHighlight | RichTextBoxFinds.None) != -1)
                                      {
                                          dicCheckingKeyCharsIndexes[chrCheckingKeyChars[intCntr]] = rtb.Find(chrCheckingKeyChars[intCntr].ToString(), intFirstIndexForChecking,
                                              rtb.GetCharIndexFromPosition(ptCurrentCharPosition), RichTextBoxFinds.NoHighlight | RichTextBoxFinds.None);
                                      }
                                      intFirstIndexForChecking++;
                                  } while (intFirstIndexForChecking != rtb.GetCharIndexFromPosition(ptCurrentCharPosition));
                                  break;
                              }
                          }
                          catch
                          {
                              dicCheckingKeyCharsIndexes[chrCheckingKeyChars[intCntr]] = -1;
                              break;
                          }
      
                          if (bolSearchCurrentLine)
                          {
                              break;
                          }
                      }
                  }
      
                  return dicCheckingKeyCharsIndexes;
              }
      
              /// <summary>
              /// Checks a line for calculating its indention level.
              /// </summary>
              /// <param name="intCharIndex">A char index</param>
              /// <param name="rtb">A RichTextBox control</param>
              /// <returns>Returns indention level of the line.</returns>
              private int CheckingIndentionLevel(int intCharIndex, RichTextBox rtb)
              {
                  int intLineNumber = GetLineNumber(intCharIndex, rtb);
                  int intIndentionLevelNumber = 0;
      
                  intCharIndex = rtb.GetFirstCharIndexFromLine(intLineNumber);
                  char chrChar = GetChar(intCharIndex, rtb);
                  if (chrChar == '\n')
                  {
                      chrChar = GetChar(++intCharIndex, rtb);
                  }
      
                  if (chrChar != ' ')
                  {
                      return 0;
                  }
                  else
                  {
                      int intSpaceCntr = 0;
                      while(chrChar == ' ')
                      {
                          chrChar = GetChar(++intCharIndex, rtb);
                          if (chrChar == ' ')
                          {
                              intSpaceCntr++;
                          }
      
                          if (intSpaceCntr % 4 == 0 && intSpaceCntr != 0)
                          {
                              intIndentionLevelNumber++;
                              intSpaceCntr = 0;
                          }
                      }
      
                      if (intSpaceCntr % 4 != 0)
                      {
                          intIndentionLevelNumber++;
                      }
                  }
      
                  return intIndentionLevelNumber;
              }
      
              /// <summary>
              /// Implements Indention to the codes
              /// </summary>
              /// <param name="intCharIndex">A char index</param>
              /// <param name="intIndentionLevel">The number of indention level</param>
              /// <param name="rtb">A RichTextBox control</param>
              private void ImplementIndention(int intCharIndex, int intIndentionLevel, RichTextBox rtb)
              {
                  intNextCharIndex = intCharIndex;
      
                  intPrevCharIndex = intCharIndex;
                  int intKeyCharsNumberInLine = 1;
                  int intCurrentLineNumber = GetLineNumber(rtb);
                  int intKeyCharLineNumber = GetLineNumber(intNextCharIndex, rtb);
                  string[] strLinesTexts;
                  Dictionary<char, int> dicResult;
      
                  do
                  {
                      rtb.SelectionStart = intPrevCharIndex;
                      dicResult = IsExistCheckingKeyChars(rtb);
                      if (dicResult[chrCheckingKeyChars[0]] != -1)
                      {
                          intKeyCharsNumberInLine++;
                          intPrevCharIndex = dicResult[chrCheckingKeyChars[0]];
                      }
                  } while (dicResult[chrCheckingKeyChars[0]] != -1);
      
                  if (!bolCheckCalling)
                  {
                      if (intCurrentLineNumber == intKeyCharLineNumber)
                      {
                          for (int intCntr = 1; intCntr <= intKeyCharsNumberInLine; intCntr++)
                          {
                              do
                              {
                                  rtb.SelectionStart = intPrevCharIndex;
                                  dicResult = IsExistCheckingKeyChars(rtb, true);
                                  if (dicResult[chrCheckingKeyChars[0]] != -1)
                                  {
      
                                      intPrevCharIndex = dicResult[chrCheckingKeyChars[0]];
                                  }
                              } while (dicResult[chrCheckingKeyChars[0]] != -1);
      
                              bolCheckCalling = true;
                              ImplementIndention(intPrevCharIndex, rtb);
                          }
                          return;
                      }
                  }
      
                  bolCheckCalling = false;
                  rtb.SelectionStart = intNextCharIndex;
                  rtb.SelectionLength = 1;
                  rtb.SelectedText = "\n" + rtb.SelectedText;
                  intCurrentLineNumber = GetLineNumber(rtb);
      
                  strLinesTexts = rtb.Lines;
                  strLinesTexts[intCurrentLineNumber] = strLinesTexts[intCurrentLineNumber].Trim();
      
                  for (int intIndentionCntr = 1; intIndentionCntr <= intIndentionLevel; intIndentionCntr++)
                  {
                      for (int intSpaceCntr = 1; intSpaceCntr <= 4; intSpaceCntr++)
                      {
                          strLinesTexts[intCurrentLineNumber] = ' ' + strLinesTexts[intCurrentLineNumber];
                      }
                  }
                  rtb.Lines = strLinesTexts;
      
                  rtb.SelectionStart = intNextCharIndex + ((intIndentionLevel * 4) + 1);
                  intNextCharIndex = rtb.SelectionStart;
                  rtb.SelectionLength = 1;
                  rtb.SelectedText = rtb.SelectedText + "\n";
                  intCurrentLineNumber = GetLineNumber(rtb);
      
                  strLinesTexts = rtb.Lines;
                  strLinesTexts[intCurrentLineNumber] = strLinesTexts[intCurrentLineNumber].Trim();
      
                  for (int intIndentionCntr = 1; intIndentionCntr <= intIndentionLevel + 1; intIndentionCntr++)
                  {
                      for (int intSpaceCntr = 1; intSpaceCntr <= 4; intSpaceCntr++)
                      {
                          strLinesTexts[intCurrentLineNumber] = ' ' + strLinesTexts[intCurrentLineNumber];
                      }
                  }
                  rtb.Lines = strLinesTexts;
                  rtb.SelectionStart = intInitialCursorPosition + ((rtb.TextLength - intInitialCursorPosition) - intRemainingCharsOfInitialText);
                  intNextCharIndex = rtb.SelectionStart;
                  intPrevCharIndex = intNextCharIndex;
              }
      
              /// <summary>
              /// Implements Indention to the codes
              /// </summary>
              /// <param name="intCharIndex">A char index</param>
              /// <param name="rtb">A RichTextBox control</param>
              private void ImplementIndention(int intCharIndex, RichTextBox rtb)
              {
                  int intIndentionLevel = CheckingIndentionLevel(intCharIndex, rtb);
                  ImplementIndention(intCharIndex, intIndentionLevel, rtb);
              }
          }
      }
      

      我希望此示例代码可以为您提供帮助。

      如果您改进了代码,请更新并分享代码。