XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Text;
using XFESystem.Console;
using XFESystem.Core;
using XFESystem.Desktop;
using XFESystem.ManagedRuntime;
using XFESystem.NativeKernel;
using XFESystem.NativeRuntime.Application;

namespace XFESystem.NativeRuntime.ConsoleApplication;

internal static class Program
{
    public const string Version = "0.3.0-dev.4";
    private const string ManagedDemoPath = "X:\\Programs\\ManagedHello\\ManagedHello.dll";

    private static int Main()
    {
        NativePlatform.Write("XFE_INDEPENDENT_APPLICATION_ENTER\nXFE_SYSTEM_EDITION|Console\nXFE_INDEPENDENT_EDITION|Console\n");
        try
        {
            global::System.Console.SetOut(new NativeDiagnosticWriter());
            global::System.Console.SetError(new NativeDiagnosticWriter());
            NativePlatform.RequireClock(); RuntimeSelfCheck.Run();
            var renderer = new ClassicConsoleRenderer(new ConsoleMemoryFramebuffer(NativePlatform.ReadFramebuffer(), NativePlatform.CompleteBoot));
            var workspace = CreateWorkspace();
            workspace.CreateDirectory("X:\\System\\Diagnostics");
            string gpuReport = NativeGpuDiagnostics.ReadReport(out bool hasRtx5090);
            workspace.WriteText("X:\\System\\Diagnostics\\Gpu.txt", gpuReport);
            workspace.WriteText("X:\\System\\Diagnostics\\Usb.txt", NativeUsbDiagnostics.ReadReport());
            var shell = new TerminalShell(workspace, Version, renderer.Columns, Math.Clamp(renderer.Rows * 8, 128, 512));
            shell.ProgramOutput.WriteLine("纯控制台版 / Console edition — C# independent kernel");
            shell.ProgramOutput.WriteLine(workspace.IsPersistent ? "U 盘工作区,文件和设置写入物理介质。\r\n" : "RAM 会话:启动 U 盘存储不可用,关机后文件不会保留。\r\n");
            if (hasRtx5090) shell.ProgramOutput.WriteLine(gpuReport);
            renderer.Render(shell);
            NativePlatform.Write("XFE_INDEPENDENT_CONSOLE_FIRST_FRAME|Width|" + renderer.Width + "|Height|" + renderer.Height +
                "|ScalePercent|" + renderer.ScalePercent + "|Presented|" + renderer.FramesPresented + "\n");
            uint capabilities = NativePlatform.InputCapabilities();
            NativePlatform.Write("XFE_INDEPENDENT_INPUT|Connected|" + ((capabilities & 1) != 0 ? 1 : 0) +
                "|Keyboard|" + (capabilities & 1) + "|Mouse|0|Wheel|" + ((capabilities >> 2) & 1) + "|Backend|PS2+xHCI|UsbHid|" + NativeUsbDiagnostics.KeyboardMouse + "\n");
            NativePlatform.Write("XFE_INDEPENDENT_CAPABILITIES|RAMOnly|"+(workspace.IsPersistent?0:1)+"|NativeNetwork|0|Gpu|0|Cuda|0|Desktop|0|Browser|0|ConsoleIL|1\n");
            Report(shell, renderer);
            Pump(shell, workspace, renderer);
            return 0;
        }
        catch (Exception error)
        {
            NativePlatform.Write("XFE_INDEPENDENT_APPLICATION_FAILED|" + error.Message + "\n");
            NativePlatform.Halt("Managed console failed: " + error.Message);
            return 1;
        }
    }

    private static IWorkspaceBinaryStorage CreateWorkspace()
    {
        var workspace = NativeWorkspace.Open();
        string readme=SystemPaths.Combine(SystemPaths.Documents,"Readme.txt");
        if(!workspace.Exists(readme))workspace.WriteText(readme, """
            XFESystem 纯控制台版 / Console edition
            自研 C# 独立内核,官方 Microsoft .NET 10 NativeAOT。
            参考以前 Rust 控制台的命令工作台、字体和配色。
            help 查看命令;上下箭头查看历史;左右/Home/End 编辑;Ctrl+C 取消。
            PageUp/PageDown 或鼠标滚轮回看输出;输入命令后返回最新输出。
            open 文本文件会在控制台显示;本版没有桌面、浏览器和图形编辑器。
            run X:\Programs\ManagedHello\ManagedHello.dll 运行 ConsoleIL 示例。
            U 盘可用时文件和设置持久保存;存储不可用时明确回退到 RAM 会话。
            X:\UsbFiles 映射启动 U 盘的 UserFiles 文件夹,可读取其中的 .NET 控制台程序。
            """);
        workspace.CreateDirectory("X:\\Programs\\ManagedHello");
        using var sample = typeof(Program).Assembly.GetManifestResourceStream("ApplicationSamples/ManagedHello.dll")
            ?? throw new InvalidOperationException("The embedded ConsoleIL sample is missing.");
        if (sample.Length > ManagedRuntimeCapabilities.MaxImageBytes) throw new InvalidDataException("Managed sample exceeds its image budget.");
        byte[] image = new byte[checked((int)sample.Length)]; sample.ReadExactly(image);
        if(!workspace.Exists(ManagedDemoPath))workspace.WriteBytes(ManagedDemoPath, image);
        string samplePath=SystemPaths.Combine(SystemPaths.Documents,"ManagedHello.dll");
        if(!workspace.Exists(samplePath))workspace.WriteBytes(samplePath,image);
        return workspace;
    }

    private static void Pump(TerminalShell shell, IWorkspaceBinaryStorage workspace, ClassicConsoleRenderer renderer)
    {
        long previous = NativePlatform.Milliseconds(), nextBlink = previous + 500, nextUsb = previous + 2000;
        bool cursor = true, dirty = false; int scrollRows = 0;
        for (;;)
        {
            long now = NativePlatform.Milliseconds();
            if (now < previous) throw new InvalidOperationException("The native monotonic clock moved backward.");
            previous = now;
            if (now >= nextUsb) { nextUsb = now + 2000; workspace.WriteText("X:\\System\\Diagnostics\\Usb.txt", NativeUsbDiagnostics.ReadReport()); }
            for (int count = 0; count < 256 && NativePlatform.ReadInput(out var report); count++)
            {
                if (report.Kind == Ps2Decoder.Pointer && report.Wheel != 0)
                { scrollRows = Math.Clamp(scrollRows + report.Wheel * 3, 0, 512); dirty = true; continue; }
                if (report.Kind == Ps2Decoder.KeyDown && report.Unicode == 0 && report.KeyCode is 0x49 or 0x149 or 0x51 or 0x151)
                {
                    scrollRows = Math.Clamp(scrollRows + (report.KeyCode is 0x49 or 0x149 ? 1 : -1) * Math.Max(1, renderer.Rows - 2), 0, 512);
                    dirty = true; continue;
                }
                if (ConsoleKeyboard.Translate(report) is not { } key) continue;
                scrollRows = 0; cursor = true; nextBlink = now + 500; dirty = true;
                if (shell.HandleKey(key.Key, key.Text) is not { } result) continue;
                if (result.OpenPath is { } opened)
                {
                    // Console files stay in this text workspace; there is no hidden GUI launch path.
                    try { shell.ProgramOutput.WriteLine(workspace.ReadText(opened).Replace("\r\n", "\n", StringComparison.Ordinal).Replace("\n", "\r\n", StringComparison.Ordinal)); }
                    catch (IOException error) { shell.ProgramOutput.WriteLine("Open failed: " + error.Message); }
                }
                if (result.ManagedProgramPath is { } path)
                {
                    renderer.Render(shell, busy: true); Report(shell, renderer, busy: true);
                    ExecuteManaged(workspace, shell.ProgramOutput, path);
                    renderer.Render(shell); Report(shell, renderer);
                    NativePlatform.Write("XFE_INDEPENDENT_CONSOLE_PRESENTED|Path|" + path + "|Frames|" + renderer.FramesPresented + "\n");
                }
                if (result.CloseRequested) shell.ProgramOutput.WriteLine("这是系统控制台会话。可使用机器的关机或重启控制结束会话。");
            }
            if (now >= nextBlink) { cursor = !cursor; nextBlink = now + 500; dirty = true; }
            if (dirty)
            {
                renderer.Render(shell, cursorVisible: cursor, scrollRows: scrollRows);
                Report(shell, renderer); dirty = false;
            }
            Thread.Sleep(1);
        }
    }

    private static void ExecuteManaged(IWorkspaceBinaryStorage workspace, TerminalTextWriter output, string path)
    {
        try
        {
            var result = new ManagedApplicationRunner().Execute(workspace.ReadBytes(path), new TerminalManagedConsole(output));
            output.Complete(); output.WriteLine("Managed ConsoleIL exit: " + result.ExitCode);
            string text = string.Concat(output.Snapshot().Cells.Select(cell => cell.Text));
            if (result.ExitCode == 0 && text.Contains("XFE_MANAGED_APP_OK", StringComparison.Ordinal) && text.Contains("XFE_MANAGED_XFECONSOLE_OK", StringComparison.Ordinal))
                NativePlatform.Write("XFE_INDEPENDENT_CONSOLE_IL_OK actual_embedded_net10_PE bounded_interpreter\n");
        }
        catch (Exception error) when (error is not OutOfMemoryException and not StackOverflowException)
        { output.Complete(); output.WriteLine("Managed program failed: " + error.Message); }
    }

    private static string lastState = "";
    private static void Report(TerminalShell shell, ClassicConsoleRenderer renderer, bool busy = false)
    {
        var snapshot = shell.ReadOutput(); var text = new StringBuilder();
        for (int row = Math.Max(0, snapshot.CursorRow - 63); row <= Math.Min(snapshot.CursorRow, snapshot.Rows - 1); row++)
        {
            var line = new StringBuilder();
            for (int column = 0; column < snapshot.Columns; column++)
            { var cell = snapshot.GetCell(column, row); if (!cell.IsContinuation) line.Append(cell.Text); }
            text.AppendLine(line.ToString().TrimEnd());
        }
        string json = "{\"Text\":" + Quote(text.ToString()) + ",\"Input\":" + Quote(shell.Input) + ",\"Prompt\":" + Quote(shell.Prompt) +
            ",\"Busy\":" + (busy ? "true" : "false") + ",\"Version\":" + Quote(shell.Version) + ",\"LastCommand\":" + Quote(shell.History.LastOrDefault() ?? "") +
            ",\"Caret\":" + shell.Caret + ",\"Columns\":" + renderer.Columns + ",\"Rows\":" + renderer.Rows + "}";
        if (json == lastState) return;
        lastState = json; NativePlatform.Write("XFE_CONSOLE_SNAPSHOT_BEGIN\n" + json + "\nXFE_CONSOLE_SNAPSHOT_END\n");
    }
    private static string Quote(string value)
    {
        var result = new StringBuilder("\"");
        foreach (char character in value)
            switch (character)
            {
                case '"': result.Append("\\\""); break; case '\\': result.Append("\\\\"); break;
                case '\n': result.Append("\\n"); break; case '\r': result.Append("\\r"); break; case '\t': result.Append("\\t"); break;
                default: if (character < 32) result.Append("\\u" + ((int)character).ToString("x4")); else result.Append(character); break;
            }
        return result.Append('"').ToString();
    }
}