代码中自动缩进括号的算法
我正在编写代码编辑器(WinForms),我想知道如何使用括号(打开和关闭)来实现{和}的自动缩进function,就像在实际的代码编辑器中一样。
— |> {和}
像这样1:
编辑器是一个名为rtb的richtextbox。
在阅读和使用代码之前,请阅读以下文本:
- 我没有足够的时间来编写更好的代码。 我只是试着为你写一个样本 。
- 我只是以简单的方式编写代码, 而不是OOP 。
- 您可以使用枚举 , 属性 , 类和其他OOP来改进代码。
- 您可以改进代码的逻辑 ; 并且您可以使用multithreading来实现更好的性能 。
- 这个样本不彻底 。 我只为“分号(;)”字符实现了一个Auto-Indention示例 。
我应该说一些使用代码的提示 :
- rtbCodes是示例项目中表单上的RichTextBox控件的名称 。
- frmCodeEditor是示例项目中表单的名称 。
您可以从以下地址下载示例项目:
4Shared – >代码编辑器的自动缩进
SendSpace – >代码编辑器的自动缩进
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); } /// /// Implements Auto-Indention. /// /// A RichTextBox control 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); } } /// /// Specifies current char based on the cursor position. /// /// A RichTextBox control /// Returns a char. private char GetChar(RichTextBox rtb) { return GetChar(rtb.SelectionStart, rtb); } /// /// Specifies a char based on the specified index. /// /// A char index /// A RichTextBox control /// Returns a char. 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); } /// /// Specifies current line number based on the cursor position. /// /// A RichTextBox control /// Returns the line number. private int GetLineNumber(RichTextBox rtb) { return GetLineNumber(rtb.GetFirstCharIndexOfCurrentLine(), rtb); } /// /// Specifies the line number based on the specified index. /// /// A char index /// A RichTextBox control /// Returns the line number. private int GetLineNumber(int intCharIndex, RichTextBox rtb) { return rtb.GetLineFromCharIndex(intCharIndex); } /// /// Implements indention for semicolon ";" character. /// /// A RichTextBox control private void ImplementIndentionForSemicolon(RichTextBox rtb) { Dictionary 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) { } /// /// Checks current and previous lines for finding key-chars. /// /// A RichTextBox control /// The search state /// Returns first occurrences of key-chars before current char. private Dictionary IsExistCheckingKeyChars(RichTextBox rtb, bool bolSearchCurrentLine = false) { GetChar(rtb); Dictionary dicCheckingKeyCharsIndexes = new Dictionary(); 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; } /// /// Checks a line for calculating its indention level. /// /// A char index /// A RichTextBox control /// Returns indention level of the line. 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; } /// /// Implements Indention to the codes /// /// A char index /// The number of indention level /// A RichTextBox control 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 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; } /// /// Implements Indention to the codes /// /// A char index /// A RichTextBox control private void ImplementIndention(int intCharIndex, RichTextBox rtb) { int intIndentionLevel = CheckingIndentionLevel(intCharIndex, rtb); ImplementIndention(intCharIndex, intIndentionLevel, rtb); } } }
我希望这个示例代码可以帮助您。
如果您改进,请更新和共享代码。
好吧,我的解决方案是错误的,但它足以让你了解它是如何工作的
我的结果:
{ { { } } }
在这里我的代码
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; } }
我希望这能帮到您