如何修复控制台编辑器中语法高亮文本的退格键Bug
控制台编辑器退格键无法删除高亮单词的修复方案
问题描述
运行提供的C#控制台编辑器代码,进入编辑器模式后输入语法高亮列表中的单词,尝试删除上一行的该类单词时,退格键失效,无法删除带语法高亮的内容。
问题根源
- 退格逻辑错误:原代码中无论光标处于文本的哪个位置,退格操作都会删除
text变量的最后一个字符,而非光标前的字符,导致删除行为和预期不符。 - 渲染逻辑不完善:仅对当前行的高亮单词重新着色,当修改其他行内容时,控制台显示未同步更新,残留的高亮内容造成视觉上的删除失效假象。
修复后的完整代码
using System; using System.Collections.Generic; using System.IO; namespace ConsoleApp { class Program { static bool isInEditorMode = false; static Dictionary<string, ConsoleColor> highlightColors = new Dictionary<string, ConsoleColor>(); static void Main(string[] args) { Console.Title = "SCRIPTER - Version 1.01"; highlightColors.Add("samip", ConsoleColor.Blue); highlightColors.Add("srijan", ConsoleColor.Blue); highlightColors.Add("regmi", ConsoleColor.Red); highlightColors.Add("<html>", ConsoleColor.DarkBlue); highlightColors.Add("</html>", ConsoleColor.DarkBlue); highlightColors.Add("<head>", ConsoleColor.Blue); highlightColors.Add("</head>", ConsoleColor.Blue); highlightColors.Add("<title>", ConsoleColor.Red); highlightColors.Add("</title>", ConsoleColor.Red); highlightColors.Add("<body>", ConsoleColor.DarkGreen); highlightColors.Add("</body>", ConsoleColor.DarkGreen); highlightColors.Add("<table>", ConsoleColor.DarkRed); highlightColors.Add("</table>", ConsoleColor.DarkRed); highlightColors.Add("<marquee>", ConsoleColor.DarkYellow); highlightColors.Add("</marquee>", ConsoleColor.DarkYellow); Console.Clear(); string input; while (true) { Console.WriteLine( @"▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ██░▄▄▄░██░▄▄▀██░▄▄▀█▄░▄██░▄▄░█▄▄░▄▄██░▄▄▄██░▄▄▀███▀███▀█▀░█████░▄▄░█▀░██ ██▄▄▄▀▀██░█████░▀▀▄██░███░▀▀░███░████░▄▄▄██░▀▀▄████░▀░███░██▀▀█░▀▄░██░██ ██░▀▀▀░██░▀▀▄██░██░█▀░▀██░██████░████░▀▀▀██░██░█████▄███▀░▀█▄▄█░▀▀░█▀░▀█ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀" ); Console.WriteLine( @" .---------. | samTime | '---------' " ); Console.WriteLine("Enter E to enter editor mode, I to open a file, or Q to quit the program."); input = Console.ReadLine(); if (input.ToUpper() == "E") { isInEditorMode = true; EditorMode(); isInEditorMode = false; } else if (input.ToUpper() == "I") { Console.WriteLine("Enter the path of the file to open: "); string filePath = Console.ReadLine(); if (File.Exists(filePath)) { string text = File.ReadAllText(filePath); isInEditorMode = true; EditorMode(text); isInEditorMode = false; } else { Console.Clear(); Console.WriteLine(filePath + " does not exist"); } } else if (input.ToUpper() == "Q") { break; } } Console.WriteLine("Press any key to exit..."); Console.ReadKey(); } static void EditorMode(string text = "") { Console.Clear(); Console.WriteLine("Editor mode. Press Ctrl+S to save, Ctrl+X to exit."); int editorTop = Console.CursorTop; int editorLeft = Console.CursorLeft; // 维护光标在文本中的索引,而非屏幕坐标 int cursorIndex = text.Length; ConsoleKeyInfo keyInfo; do { keyInfo = Console.ReadKey(true); if (isInEditorMode) { if (keyInfo.Modifiers == ConsoleModifiers.Control && keyInfo.Key == ConsoleKey.S) { Console.Clear(); SaveFile(text); return; } else if (keyInfo.Modifiers == ConsoleModifiers.Control && keyInfo.Key == ConsoleKey.X) { Console.Clear(); return; } else if (keyInfo.Key == ConsoleKey.Backspace && cursorIndex > 0) { // 删除光标前的字符 text = text.Remove(cursorIndex - 1, 1); cursorIndex--; } else if (keyInfo.Key == ConsoleKey.LeftArrow && cursorIndex > 0) { cursorIndex--; } else if (keyInfo.Key == ConsoleKey.RightArrow && cursorIndex < text.Length) { cursorIndex++; } else if (keyInfo.Key == ConsoleKey.Enter) { text = text.Insert(cursorIndex, Environment.NewLine); cursorIndex += Environment.NewLine.Length; } else if (!char.IsControl(keyInfo.KeyChar)) { text = text.Insert(cursorIndex, keyInfo.KeyChar.ToString()); cursorIndex++; } // 重新渲染整个编辑器内容 RenderEditorContent(text, editorTop, editorLeft); // 将光标设置到正确的屏幕位置 SetCursorToIndex(cursorIndex, text, editorTop, editorLeft); } } while (true); } static void RenderEditorContent(string text, int editorTop, int editorLeft) { Console.SetCursorPosition(editorLeft, editorTop); // 清除编辑器区域的旧内容 for (int i = editorTop; i < Console.WindowHeight; i++) { Console.SetCursorPosition(editorLeft, i); Console.Write(new string(' ', Console.WindowWidth - editorLeft)); } // 重新写入文本并应用高亮 string[] lines = text.Split(new[] { Environment.NewLine }, StringSplitOptions.None); for (int lineNum = 0; lineNum < lines.Length; lineNum++) { int currentLine = editorTop + lineNum; if (currentLine >= Console.WindowHeight) break; Console.SetCursorPosition(editorLeft, currentLine); string line = lines[lineNum]; // 先写入默认颜色的整行文本 Console.ForegroundColor = ConsoleColor.Gray; Console.Write(line); Console.ResetColor(); // 对行内的高亮单词重新着色 foreach (var highlight in highlightColors) { string word = highlight.Key; int index = line.IndexOf(word); while (index >= 0) { Console.SetCursorPosition(editorLeft + index, currentLine); Console.ForegroundColor = highlight.Value; Console.Write(word); Console.ResetColor(); index = line.IndexOf(word, index + word.Length); } } } } static void SetCursorToIndex(int cursorIndex, string text, int editorTop, int editorLeft) { if (cursorIndex == 0) { Console.SetCursorPosition(editorLeft, editorTop); return; } string subText = text.Substring(0, cursorIndex); int lineCount = subText.Split(new[] { Environment.NewLine }, StringSplitOptions.None).Length - 1; int currentLine = editorTop + lineCount; int lastNewLineIndex = subText.LastIndexOf(Environment.NewLine); int column = lastNewLineIndex == -1 ? cursorIndex : cursorIndex - (lastNewLineIndex + Environment.NewLine.Length); Console.SetCursorPosition(editorLeft + column, currentLine); } static void SaveFile(string text) { Console.Clear(); Console.WriteLine("Enter file name with extension: "); string fileName = Console.ReadLine(); File.WriteAllText(fileName, text); Console.Clear(); Console.WriteLine("File saved as " + fileName + "."); Console.WriteLine("Do you want to open the file? (Y/N)"); string input = Console.ReadLine(); if (input.ToUpper() == "Y") { System.Diagnostics.Process.Start(fileName); Console.Clear(); } else if (input.ToUpper() == "N") { Console.Clear(); } } } }
关键改动说明
- 光标位置管理:改用
cursorIndex维护光标在文本字符串中的索引,替代原有的屏幕坐标(currentLine/currentPosition),确保光标位置和文本内容完全同步。 - 修复退格逻辑:退格时删除
cursorIndex前的字符,而非文本末尾字符,符合常规编辑器的删除行为。 - 全量渲染机制:每次内容变化时,重新渲染整个编辑器区域的文本并应用高亮,彻底解决高亮内容残留的问题。
- 光标定位函数:新增
SetCursorToIndex函数,根据文本索引计算对应的屏幕坐标,确保光标始终显示在正确位置。
内容的提问来源于stack exchange,提问作者Sam8848
相关产品推荐
相关产品推荐

