2013-05-08 85 views
4

即時通訊工作在代碼編輯器(WinForms),我想知道如何執行{和}的功能,特別是使用方括號(打開和關閉)的自動縮進,就像在實際的代碼中一樣編輯。在代碼中自動縮進括號的算法

--- |> {和}

這樣1:

enter image description here

編輯器是一個名爲RTB的RichTextBox。

+0

我不確定你是否要求一套要求...或代碼示例 – lexu 2013-05-08 05:02:06

+0

代碼示例先生@lexu – Elegiac 2013-05-08 05:03:10

+0

我推測,你可以制定一個遞歸函數,當用戶關閉最後一次關閉的捲髮支架和鍛鍊直到你找到一個開放的大括號。並在迭代的每個階段追加製表符/所需的縮進。 – Nair 2013-05-08 05:08:11

回答

2

請在閱讀之前閱讀以下文章次使用代碼:

  1. 我已經沒有足夠的時間寫出更好的代碼。我只試着給你寫樣品
  2. 我只寫代碼以簡單的方式,不是OOP
  3. 您可以使用枚舉屬性OOP其他的事情提高了代碼。
  4. 您可以改進代碼的邏輯;並且您可以使用多線程來實現更好的性能
  5. 此示例不徹底。我僅對「分號(;)」字符實施了自動縮進示例。

我應該說一些提示使用代碼:

  1. rtbCodes是示例項目的窗體上的RichTextBox控件的名稱。
  2. frmCodeEditor是示例項目中的名稱。

您可以從以下地址下載樣本項目:

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); 
     } 
    } 
} 

我希望這個示例代碼可以幫助你。

如果您改進了,請更新並共享代碼。

+0

我能說什麼。很多努力和時間爲這個腳本提供了藉口。生病記住,並做所有這些話......非常感謝先生!這樣一個真棒腳本更多的權力! :) 上帝保佑 ...... – Elegiac 2013-07-24 09:28:57

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; 
    } 
} 

我希望這將幫你

+0

生病請嘗試這個先生等待:D – Elegiac 2013-05-08 09:42:39

+1

+1幫助先生。即使它有錯誤,當我鍵入文本,我按空間,但它確定我知道^^一個星期後沒有更好的答案生病接受這一點。非常感謝您的幫助!!! – Elegiac 2013-05-08 09:56:43

+0

@Elegiac你會需要一些邏輯的courser位置('rtb.SelectionStart')和一些密鑰的不提高'KeyPressEvent'這也提供了一些麻煩這是一個非常棘手的問題:-) – WiiMaxx 2013-05-08 09:59:58

相關問題