2013-05-08 2 views
4

im работает над программным редактором (WinForms), и я хочу знать, как выполнять функцию {и}, в частности, автозадачу с использованием скобок (открывать и закрывать), как в реальном коде редактор .Алгоритм для автоиндексирующих скобок в коде

--- |> {и}

как этот 1:

enter image description here

Редактор был назван RichTextBox RTB.

+0

Я не уверен, если вы просите набор требований ... или образцы кода – lexu

+0

образец кода сэр @lexu – Elegiac

+0

я предполагаю, вы можете тренировки рекурсивной функции, которые инициируют если пользователь закрывает последнюю закрытую фигурные кронштейн и тренировки, пока не найдете открытую фигурную скобку. И добавление вкладок/требуемое отступы на каждом этапе итерации. – Nair

ответ

2

Прочтите следующие тексты, прежде чем читать й с использованием кодов:

  1. Я не хватает времени для написания более кодов. Я только пытался написать образец для вас.
  2. Я просто написал коды простым способом, не в ООП.
  3. Вы можете улучшить коды с помощью перечислений, Свойства, Классов и других вещей ООП.
  4. Вы можете исправить логическую схему ; и вы можете использовать Multi-Threading для достижения лучшей производительности.
  5. Этот образец не является исчерпывающим.. Я применил только пример Auto-Indention для символа «точка с запятой (;)».

Я должен сказать, некоторые советы для использования кодов:

  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

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

плохо попробуйте этот сэр wait: D – Elegiac

+1

+1 за помощь сэр. даже если у него есть ошибка, когда я печатаю текст, и я нажимаю пробел, но он в порядке, я получаю идею ^^ через неделю без лучшего ответа, плохо согласен с этим. Большое спасибо за помощь!!! – Elegiac

+0

@Elegiac вам понадобится какая-то логика для позиции курсора ('rtb.SelectionStart'), а некоторые Key's не поднимают' KeyPressEvent', что также вызывает некоторые проблемы, это очень сложная проблема :-) – WiiMaxx

Смежные вопросы