You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复控制台编辑器中语法高亮文本的退格键Bug

控制台编辑器退格键无法删除高亮单词的修复方案

问题描述

运行提供的C#控制台编辑器代码,进入编辑器模式后输入语法高亮列表中的单词,尝试删除上一行的该类单词时,退格键失效,无法删除带语法高亮的内容。

问题根源

  1. 退格逻辑错误:原代码中无论光标处于文本的哪个位置,退格操作都会删除text变量的最后一个字符,而非光标前的字符,导致删除行为和预期不符。
  2. 渲染逻辑不完善:仅对当前行的高亮单词重新着色,当修改其他行内容时,控制台显示未同步更新,残留的高亮内容造成视觉上的删除失效假象。

修复后的完整代码

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

关键改动说明

  1. 光标位置管理:改用cursorIndex维护光标在文本字符串中的索引,替代原有的屏幕坐标(currentLine/currentPosition),确保光标位置和文本内容完全同步。
  2. 修复退格逻辑:退格时删除cursorIndex前的字符,而非文本末尾字符,符合常规编辑器的删除行为。
  3. 全量渲染机制:每次内容变化时,重新渲染整个编辑器区域的文本并应用高亮,彻底解决高亮内容残留的问题。
  4. 光标定位函数:新增SetCursorToIndex函数,根据文本索引计算对应的屏幕坐标,确保光标始终显示在正确位置。

内容的提问来源于stack exchange,提问作者Sam8848

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 07:52:02