本文介绍了算法代码自动缩进支架的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
即时通讯工作的一个代码编辑器(的WinForms),我想知道怎么做的功能{和}专门用括号就像在实际的代码编辑器(打开和关闭)自动缩进。
like this 1:
Editor was a richtextbox named rtb.
解决方案
Please read the following texts before reading and using codes:
- I've not enough time for writing better codes. I have only tried to write a sample for you.
- I have only written the codes in a simple way, not in OOP.
- You can improve the codes with using Enums, Properties, Classes and other things of OOP.
- You can improve the logic of the codes; and you can use Multi-Threading for achieve to better performance.
- 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:
- rtbCodes is the name of the RichTextBox control on the form in the sample project.
- 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.
这篇关于算法代码自动缩进支架的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!