Frage

im working on a code-editor (WinForms) and i want to know how to do function of { and } specifically the auto-indention using brackets (open and close) like in actual code editor .

---|> { and }

like this 1:

enter image description here

Editor was a richtextbox named rtb.

War es hilfreich?

Lösung

Please read the following texts before reading and using codes:

  1. I've not enough time for writing better codes. I have only tried to write a sample for you.
  2. I have only written the codes in a simple way, not in OOP.
  3. You can improve the codes with using Enums, Properties, Classes and other things of OOP.
  4. You can improve the logic of the codes; and you can use Multi-Threading for achieve to better performance.
  5. This sample isn't thorough. I has only implemented an Auto-Indention example for "semicolon (;)" character.

I should say some tips for using the codes:

  1. rtbCodes is the name of the RichTextBox control on the form in the sample project.
  2. frmCodeEditor is the name of the form in the sample project.

You can download the sample project from the following addresses:

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

I hope that this sample codes can help you.

Please update and share codes, if you improve them.

Andere Tipps

ok my solution is buggy but it's enough that you get the idea of how it works

my result:

{
        {
                {
                        }
                }
        }

and here my Code

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

i hope this will help you

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top