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