20 Commits

Author SHA1 Message Date
Leonmmcoset
ec7e0978d3 增加设置项MaxLoginAttempts(默认3) 2026-02-28 19:39:48 +08:00
Leonmmcoset
c5fc081977 hex命令 2026-02-28 19:24:02 +08:00
Leonmmcoset
58df162054 多任务 2026-02-28 16:30:25 +08:00
Leonmmcoset
02ff8295ef 修复help命令 2026-02-27 22:42:26 +08:00
Leonmmcoset
b67e0e7a03 更新help命令列表 2026-02-27 22:33:39 +08:00
Leonmmcoset
fefb7e737a lua2cla&cla命令 2026-02-27 21:39:22 +08:00
Leonmmcoset
c83988458a 更新文档 2026-02-26 22:36:40 +08:00
Leonmmcoset
ffbc58eb40 Nano超级强大功能更新 2026-02-26 21:12:06 +08:00
Leonmmcoset
c1e0651e4b 更好的Lua代码高亮 2026-02-26 18:38:07 +08:00
Leonmmcoset
5f4d97729a 移除颜色快 2026-02-26 13:47:47 +08:00
Leonmmcoset
e8e45ef7ae 更改些东西 2026-02-26 13:33:53 +08:00
Leonmmcoset
2e8ef4ef91 更新Cosmos+弃用UEFI
弃用UEFI原因: UEFI不支持VGA Text Mode
2026-02-25 18:52:53 +08:00
Leonmmcoset
0724502225 盘符操控 2026-02-25 16:51:27 +08:00
Leonmmcoset
87d30be421 Merge branch 'main' of https://github.com/Leonmmcoset/CMLeonOS 2026-02-25 15:33:48 +08:00
Leonmmcoset
9c52f9288b edit命令重定向到nano 2026-02-25 15:33:46 +08:00
LeonMMcoset
969384d25f 修改打错字的README 2026-02-25 11:07:13 +08:00
Leonmmcoset
9b783e057a 增加显示颜色测试 2026-02-24 21:48:08 +08:00
Leonmmcoset
14149aab9d 语法高亮 2026-02-24 21:15:38 +08:00
Leonmmcoset
e0e7da7ac2 用户名空白检测+修复一重大bug 2026-02-24 20:09:10 +08:00
Leonmmcoset
0386511a00 增加版权信息 2026-02-19 17:37:42 +08:00
28 changed files with 2097 additions and 84 deletions

2
.gitignore vendored
View File

@@ -56,3 +56,5 @@ coverage/
# Release files
*.release
main.map

View File

@@ -1 +1 @@
2026-02-19 17:19:17
2026-02-28 19:35:58

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
@@ -20,15 +20,17 @@
<Description>Use VMware Player or Workstation to deploy and debug.</Description>
<PxeInterface>192.168.0.8</PxeInterface>
<CompressionType>Gzip</CompressionType>
<BinFormat>Elf</BinFormat>
<BinFormat>Bin</BinFormat>
<DebugEnabled>False</DebugEnabled>
<CompileVBEMultiboot>False</CompileVBEMultiboot>
<RemoveBootDebugOutput>False</RemoveBootDebugOutput>
<RemoveBootDebugOutput>True</RemoveBootDebugOutput>
<CosmosDisableDebugger>true</CosmosDisableDebugger>
<CosmosDebugLevel>None</CosmosDebugLevel>
<OptimizationLevel>2</OptimizationLevel>
<VBEResolution>800x600x32</VBEResolution>
<RunPostBuildEvent>Always</RunPostBuildEvent>
<Timeout>1</Timeout>
<UseUEFI>False</UseUEFI>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@@ -89,7 +91,7 @@
<PackageReference Include="Cosmos.System2_Plugs" Version="0.1.0-localbuild20260201071815" />
<PackageReference Include="CosmosFtpServer" Version="1.0.9" />
<PackageReference Include="CosmosHttp" Version="1.0.4" />
<PackageReference Include="IL2CPU.API" Version="0.1.0-localbuild20260203125852" />
<PackageReference Include="IL2CPU.API" Version="0.1.0-localbuild20260225062300" />
</ItemGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">

View File

@@ -1 +1 @@
8e60a49
c5fc081

View File

@@ -28,9 +28,14 @@ namespace CMLeonOS
// 创建全局CosmosVFS实例
public static Sys.FileSystem.CosmosVFS fs = new Sys.FileSystem.CosmosVFS();
public static Shell shell;
public static UserSystem userSystem;
public static void ExecuteCommand(string command)
{
var tempShell = new Shell(userSystem);
tempShell.ExecuteCommand(command);
}
public static bool FixMode = false;
public static DateTime SystemStartTime;
@@ -71,8 +76,8 @@ namespace CMLeonOS
}
Console.Clear();
Console.WriteLine("Kernel load done!");
Console.WriteLine(@"-------------------------------------------------");
// Console.WriteLine("Kernel load done!");
// Console.WriteLine(@"----------------------------------------------------------");
Console.WriteLine(@" ____ __ __ _ ___ ____ ");
Console.WriteLine(@" / ___| \/ | | ___ ___ _ __ / _ \/ ___| ");
Console.WriteLine(@" | | | |\/| | | / _ \/ _ \| '_ \| | | \___ \ ");
@@ -80,8 +85,8 @@ namespace CMLeonOS
Console.WriteLine(@" \____|_| |_|_____\___|\___/|_| |_|____/|____/ ");
Console.WriteLine();
Console.WriteLine("The CMLeonOS Project");
Console.WriteLine("By LeonOS 2 Developement Team");
Console.WriteLine(@"-------------------------------------------------");
Console.WriteLine("(C) LeonOS 2 Developer Team 2025-2026. All rights reserved.");
Console.WriteLine(@"----------------------------------------------------------");
// 注册VFS
_logger.Info("Kernel", "Starting VFS initialization");
@@ -248,12 +253,11 @@ namespace CMLeonOS
_logger.Info("Kernel", $"User '{userSystem.CurrentUsername}' logged in successfully");
// 登录成功后初始化Shell
shell = new Shell(userSystem);
// 检查并执行启动脚本
ExecuteStartupScript();
ExecuteStartupTest();
if (System.IO.File.Exists("0:\\system\\zen"))
{
Console.WriteLine("=====================================");
@@ -280,10 +284,14 @@ namespace CMLeonOS
Console.WriteLine("A bug brings new wake, a line brings new shine.");
}
// 运行Shell用户可以输入exit退出
_logger.Info("Kernel", "Starting Shell");
shell.Run();
_logger.Info("Kernel", "Shell exited");
// 运行Shell进程用户可以输入exit退出
_logger.Info("Kernel", "Starting Shell process");
var shellProcess = new ShellProcess(userSystem);
ProcessManager.AddProcess(shellProcess);
shellProcess.TryStart();
shellProcess.TryRun();
shellProcess.TryStop();
_logger.Info("Kernel", "Shell process exited");
// 如果用户输入了exitShell.Run()会返回,继续循环
}
@@ -438,7 +446,10 @@ namespace CMLeonOS
}
Console.WriteLine("Executing startup script...");
Console.WriteLine("--------------------------------");
// Console.WriteLine("--------------------------------");
// 创建临时 Shell 实例来执行启动脚本
var tempShell = new Shell(userSystem);
// 逐行执行命令
foreach (string line in lines)
@@ -451,10 +462,10 @@ namespace CMLeonOS
// 执行命令
// Console.WriteLine($"Executing: {line}");
shell.ExecuteCommand(line);
tempShell.ExecuteCommand(line);
}
Console.WriteLine("--------------------------------");
// Console.WriteLine("--------------------------------");
_logger.Success("Kernel", "Startup script execution completed");
}
else
@@ -471,6 +482,52 @@ namespace CMLeonOS
}
}
private void ExecuteStartupTest()
{
Console.WriteLine("------------------------------------------------------");
Console.WriteLine($"Welcome to {Version.DisplayVersion}");
Console.WriteLine("* Documentation: https://cmleonos.jjmm.ink/");
Console.WriteLine("* Forum: https://lbbs.ecuil.com/#/category/10");
// Console.WriteLine("");
// 感觉排版有点割裂,先注释掉
// Console.BackgroundColor = ConsoleColor.Red;
// Console.Write(" ");
// Console.BackgroundColor = ConsoleColor.Yellow;
// Console.Write(" ");
// Console.BackgroundColor = ConsoleColor.Green;
// Console.Write(" ");
// Console.BackgroundColor = ConsoleColor.Cyan;
// Console.Write(" ");
// Console.BackgroundColor = ConsoleColor.Blue;
// Console.Write(" ");
// Console.BackgroundColor = ConsoleColor.Magenta;
// Console.Write(" ");
// Console.BackgroundColor = ConsoleColor.White;
// Console.Write(" ");
// Console.BackgroundColor = ConsoleColor.DarkBlue;
// Console.Write(" ");
// Console.BackgroundColor = ConsoleColor.DarkCyan;
// Console.Write(" ");
// Console.BackgroundColor = ConsoleColor.DarkGreen;
// Console.Write(" ");
// Console.BackgroundColor = ConsoleColor.DarkYellow;
// Console.Write(" ");
// Console.BackgroundColor = ConsoleColor.DarkRed;
// Console.Write(" ");
// Console.BackgroundColor = ConsoleColor.Gray;
// Console.Write(" ");
// Console.BackgroundColor = ConsoleColor.DarkGray;
// Console.Write(" ");
// Console.BackgroundColor = ConsoleColor.DarkMagenta;
// Console.Write(" ");
// Console.BackgroundColor = ConsoleColor.Black;
// Console.Write(" ");
// Console.WriteLine("");
// Console.ResetColor();
Console.WriteLine("------------------------------------------------------");
}
private string FormatBytes(long bytes)
{
string[] units = { "B", "KB", "MB", "GB", "TB" };
@@ -488,10 +545,7 @@ namespace CMLeonOS
protected override void Run()
{
if (shell != null)
{
shell.Run();
}
ProcessManager.Yield();
}
}
}

View File

@@ -1,2 +1,2 @@
# CMLeanOS 源代码仓库
# CMLeonOS 源代码仓库
需要 .NET 6.0 或更高版本Cosmos版本为最新的修改版DevKit。

View File

@@ -11,7 +11,8 @@ namespace CMLeonOS.Settings
private static Dictionary<string, string> defaultSettings = new Dictionary<string, string>
{
{ "LoggerEnabled", "true" }
{ "LoggerEnabled", "true" },
{ "MaxLoginAttempts", "3" }
};
public static bool LoggerEnabled
@@ -31,6 +32,26 @@ namespace CMLeonOS.Settings
}
}
public static int MaxLoginAttempts
{
get
{
if (settings.TryGetValue("MaxLoginAttempts", out string value))
{
if (int.TryParse(value, out int result))
{
return result;
}
}
return 3;
}
set
{
settings["MaxLoginAttempts"] = value.ToString();
SaveSettings();
}
}
public static void LoadSettings()
{
settings.Clear();

View File

@@ -16,7 +16,7 @@ namespace CMLeonOS
private static bool ContainsInvalidChars(string input)
{
char[] invalidChars = { '<', '>', ':', '"', '|', '?', '*' };
char[] invalidChars = { '<', '>', '"', '|', '?', '*' };
foreach (char c in invalidChars)
{
if (input.Contains(c.ToString()))
@@ -59,6 +59,18 @@ namespace CMLeonOS
return;
}
if (path == @"0:\")
{
currentDirectory = @"0:\";
return;
}
if (path == @"1:\")
{
currentDirectory = @"1:\";
return;
}
string fullPath = GetFullPath(path);
try
@@ -308,7 +320,11 @@ namespace CMLeonOS
{
if (File.Exists(fullPath))
{
return File.ReadAllText(fullPath);
using (FileStream fs = new FileStream(fullPath, FileMode.Open, FileAccess.Read))
using (StreamReader sr = new StreamReader(fs))
{
return sr.ReadToEnd();
}
}
else
{
@@ -389,15 +405,15 @@ namespace CMLeonOS
return currentDirectory;
}
char[] invalidChars = { '<', '>', ':', '"', '|', '?', '*' };
foreach (char c in invalidChars)
{
if (path.Contains(c.ToString()))
{
Console.WriteLine($"Error: Invalid character in path: '{c}'");
return currentDirectory;
}
}
//char[] invalidChars = { '<', '>', ':', '"', '|', '?', '*' };
//foreach (char c in invalidChars)
//{
// if (path.Contains(c.ToString()))
// {
// Console.WriteLine($"Error: Invalid character in path: '{c}'");
// return currentDirectory;
// }
//}
if (path.Contains("//") || path.Contains("\\\\"))
{
@@ -410,6 +426,11 @@ namespace CMLeonOS
return path;
}
if (path.StartsWith(@"1:\"))
{
return path;
}
if (path == ".")
{
return currentDirectory;
@@ -417,16 +438,16 @@ namespace CMLeonOS
if (path == "..")
{
if (currentDirectory == @"0:\")
if (currentDirectory == @"0:\" || currentDirectory == @"1:\")
{
return @"0:\";
return currentDirectory;
}
else
{
int lastSlash = currentDirectory.LastIndexOf('\\');
if (lastSlash == 2) // 0:\
if (lastSlash == 2) // 0:\ or 1:\
{
return @"0:\";
return currentDirectory.Substring(0, 3);
}
else
{
@@ -437,7 +458,7 @@ namespace CMLeonOS
if (path.StartsWith("../") || path.StartsWith("..\\"))
{
if (currentDirectory == @"0:\")
if (currentDirectory == @"0:\" || currentDirectory == @"1:\")
{
Console.WriteLine("Error: Cannot go above root directory");
return currentDirectory;
@@ -468,9 +489,9 @@ namespace CMLeonOS
for (int i = 0; i < level; i++)
{
int lastSlash = resultPath.LastIndexOf('\\');
if (lastSlash == 2) // 0:\
if (lastSlash == 2) // 0:\ or 1:\
{
resultPath = @"0:\";
resultPath = resultPath.Substring(0, 3);
}
else
{

184
System/Process.cs Normal file
View File

@@ -0,0 +1,184 @@
using System;
using System.Collections.Generic;
using Sys = Cosmos.System;
namespace CMLeonOS
{
public enum ProcessType
{
Service,
Application,
Background
}
public abstract class Process
{
private protected Process(string name, ProcessType type)
{
Name = name;
Type = type;
}
private protected Process(string name, ProcessType type, Process parent)
{
Name = name;
Type = type;
Parent = parent;
}
internal ulong Id { get; set; }
internal List<string> Args { get; private set; }
internal string Name { get; set; }
internal ProcessType Type { get; private set; }
internal DateTime Created { get; private set; } = DateTime.Now;
internal bool IsRunning { get; private set; } = false;
internal bool Swept { get; set; } = false;
internal bool Critical { get; set; } = false;
internal Process Parent { get; set; }
public virtual void Start()
{
if (Type == ProcessType.Service)
{
CMLeonOS.Logger.Logger.Instance.Info("Process", $"Service starting: {Name}");
}
IsRunning = true;
}
public abstract void Run();
public virtual void Stop()
{
if (Type == ProcessType.Service)
{
CMLeonOS.Logger.Logger.Instance.Info("Process", $"Service stopping: {Name}");
}
IsRunning = false;
foreach (Process process in ProcessManager.Processes)
{
if (process.Parent == this && process.IsRunning)
{
process.TryStop();
}
}
}
public void TryRun()
{
try
{
Run();
}
catch (Exception e)
{
if (Critical)
{
Console.Clear();
Console.BackgroundColor = ConsoleColor.Blue;
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine();
Console.WriteLine("========================================");
Console.WriteLine(" CRITICAL PROCESS CRASHED");
Console.WriteLine("========================================");
Console.WriteLine();
Console.WriteLine($"Process: {Name}");
Console.WriteLine($"ID: {Id}");
Console.WriteLine();
Console.WriteLine("Error:");
Console.WriteLine(e.ToString());
Console.WriteLine();
Console.WriteLine("Press any key to reboot...");
Console.ReadKey();
Sys.Power.Reboot();
}
else
{
CMLeonOS.Logger.Logger.Instance.Error("Process", $"Process \"{Name}\" ({Id}) crashed: {e.ToString()}");
TryStop();
}
}
}
public void TryStart()
{
try
{
Start();
}
catch (Exception e)
{
if (Critical)
{
Console.Clear();
Console.BackgroundColor = ConsoleColor.Blue;
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine();
Console.WriteLine("========================================");
Console.WriteLine(" CRITICAL PROCESS CRASHED");
Console.WriteLine("========================================");
Console.WriteLine();
Console.WriteLine($"Process: {Name}");
Console.WriteLine($"ID: {Id}");
Console.WriteLine();
Console.WriteLine("Error:");
Console.WriteLine(e.ToString());
Console.WriteLine();
Console.WriteLine("Press any key to reboot...");
Console.ReadKey();
Sys.Power.Reboot();
}
else
{
CMLeonOS.Logger.Logger.Instance.Error("Process", $"Process \"{Name}\" ({Id}) crashed while starting: {e.ToString()}");
TryStop();
}
}
}
public void TryStop()
{
try
{
Stop();
}
catch (Exception e)
{
IsRunning = false;
if (Critical)
{
Console.Clear();
Console.BackgroundColor = ConsoleColor.Blue;
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine();
Console.WriteLine("========================================");
Console.WriteLine(" CRITICAL PROCESS CRASHED");
Console.WriteLine("========================================");
Console.WriteLine();
Console.WriteLine($"Process: {Name}");
Console.WriteLine($"ID: {Id}");
Console.WriteLine();
Console.WriteLine("Error:");
Console.WriteLine(e.ToString());
Console.WriteLine();
Console.WriteLine("Press any key to reboot...");
Console.ReadKey();
Sys.Power.Reboot();
}
else
{
CMLeonOS.Logger.Logger.Instance.Error("Process", $"Process \"{Name}\" ({Id}) crashed while stopping: {e.ToString()}");
}
}
}
}
}

92
System/ProcessManager.cs Normal file
View File

@@ -0,0 +1,92 @@
using System.Collections.Generic;
namespace CMLeonOS
{
public static class ProcessManager
{
public static List<Process> Processes = new List<Process>();
private static ulong nextProcessId = 0;
public static Process AddProcess(Process parent, Process process)
{
process.Parent = parent;
AddProcess(process);
return process;
}
public static Process AddProcess(Process process)
{
if (Processes.Contains(process))
return process;
process.Id = nextProcessId;
nextProcessId++;
Processes.Add(process);
return process;
}
public static void Sweep()
{
for (int i = Processes.Count - 1; i >= 0; i--)
{
if (!Processes[i].IsRunning)
{
Processes.Remove(Processes[i]);
}
}
}
public static void Yield()
{
for (int i = Processes.Count - 1; i >= 0; i--)
{
Process process = Processes[i];
if (process.IsRunning)
{
process.TryRun();
}
}
}
public static Process GetProcessById(ulong processId)
{
foreach (Process process in Processes)
{
if (process.Id == processId) return process;
}
return null;
}
public static Process GetProcessByName(string name)
{
foreach (Process process in Processes)
{
if (process.Name == name) return process;
}
return null;
}
public static T GetProcess<T>()
{
foreach (Process process in Processes)
{
if (process is T processT) return processT;
}
return default;
}
public static void StopAll()
{
for (int i = Processes.Count - 1; i >= 0; i--)
{
Process process = Processes[i];
process.TryStop();
}
}
}
}

63
System/ShellProcess.cs Normal file
View File

@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using CMLeonOS.Commands;
using CMLeonOS.shell;
namespace CMLeonOS
{
public class ShellProcess : Process
{
private Shell shell;
public ShellProcess(UserSystem userSystem) : base("Shell", ProcessType.Application)
{
shell = new Shell(userSystem);
}
public override void Run()
{
CMLeonOS.Logger.Logger.Instance.Info("Shell", "Shell process started");
try
{
shell.Run();
}
catch (Exception e)
{
CMLeonOS.Logger.Logger.Instance.Error("Shell", $"Shell crashed: {e.ToString()}");
}
CMLeonOS.Logger.Logger.Instance.Info("Shell", "Shell process stopped");
}
}
public class CommandProcess : Process
{
private string command;
private string args;
private Shell shell;
public CommandProcess(string command, string args, Shell shell) : base($"Command_{command}", ProcessType.Application)
{
this.command = command;
this.args = args;
this.shell = shell;
}
public override void Run()
{
CMLeonOS.Logger.Logger.Instance.Info($"Command_{command}", $"Executing command: {command} {args}");
try
{
CommandList.ProcessCommand(shell, command, args);
}
catch (Exception e)
{
CMLeonOS.Logger.Logger.Instance.Error($"Command_{command}", $"Command failed: {e.ToString()}");
}
CMLeonOS.Logger.Logger.Instance.Info($"Command_{command}", $"Command completed: {command}");
}
}
}

View File

@@ -5,6 +5,8 @@ using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Sys = Cosmos.System;
using CMLeonOS.Logger;
using CMLeonOS.Settings;
namespace CMLeonOS
{
@@ -23,6 +25,8 @@ namespace CMLeonOS
private List<User> users;
public bool fixmode = Kernel.FixMode;
private User currentLoggedInUser;
private static CMLeonOS.Logger.Logger _logger = CMLeonOS.Logger.Logger.Instance;
private Dictionary<string, int> loginAttempts = new Dictionary<string, int>();
public User CurrentLoggedInUser
{
@@ -55,7 +59,7 @@ namespace CMLeonOS
private static bool ContainsInvalidChars(string input)
{
char[] invalidChars = { '<', '>', ':', '"', '|', '?', '*', '/', '\\' };
char[] invalidChars = { '<', '>', ':', '"', '|', '?', '*', '/', '\\', ' ' };
foreach (char c in invalidChars)
{
if (input.Contains(c.ToString()))
@@ -405,7 +409,7 @@ namespace CMLeonOS
{
CMLeonOS.UI.TUIHelper.SetColors(global::System.ConsoleColor.Red, global::System.ConsoleColor.Black);
global::System.Console.SetCursorPosition(7, 24);
global::System.Console.Write("Username contains invalid characters: < > : \" | ? / \\ ");
global::System.Console.Write("Username contains invalid characters: < > : \" | ? * / \\ space");
CMLeonOS.UI.TUIHelper.SetColors(global::System.ConsoleColor.White, global::System.ConsoleColor.Black);
global::System.Console.SetCursorPosition(7, 7);
global::System.Console.Write("Username: ");
@@ -519,7 +523,7 @@ namespace CMLeonOS
{
try
{
Console.WriteLine($"Creating user folder for {username}...");
_logger.Info("UserSystem", $"Creating user folder for {username}...");
// 在user文件夹下创建用户文件夹
string userFolderPath = Path.Combine(@"0:\user", username);
@@ -528,16 +532,16 @@ namespace CMLeonOS
if (!Directory.Exists(userFolderPath))
{
Directory.CreateDirectory(userFolderPath);
Console.WriteLine($"Created user folder for {username}.");
_logger.Info("UserSystem", $"Created user folder for {username}.");
}
else
{
Console.WriteLine($"User folder for {username} already exists.");
_logger.Info("UserSystem", $"User folder for {username} already exists.");
}
}
catch (Exception ex)
{
ShowError($"Error creating user folder: {ex.Message}");
_logger.Error("UserSystem", $"Error creating user folder for {username}: {ex.Message}");
}
}
@@ -591,13 +595,37 @@ namespace CMLeonOS
if (foundUser.Password != hashedInputPassword)
{
string usernameLower = username.ToLower();
if (!loginAttempts.ContainsKey(usernameLower))
{
loginAttempts[usernameLower] = 0;
}
loginAttempts[usernameLower]++;
int attempts = loginAttempts[usernameLower];
int maxAttempts = Settings.SettingsManager.MaxLoginAttempts;
if (attempts >= maxAttempts)
{
CMLeonOS.UI.TUIHelper.SetColors(global::System.ConsoleColor.Red, global::System.ConsoleColor.Black);
global::System.Console.SetCursorPosition(17, 24);
global::System.Console.Write($"Maximum login attempts ({maxAttempts}) reached. ");
global::System.Console.SetCursorPosition(17, 25);
global::System.Console.Write("Please restart to enter password again. ");
global::System.Threading.Thread.Sleep(3000);
Sys.Power.Reboot();
}
CMLeonOS.UI.TUIHelper.SetColors(global::System.ConsoleColor.Red, global::System.ConsoleColor.Black);
global::System.Console.SetCursorPosition(17, 24);
global::System.Console.Write("Invalid password. ");
global::System.Console.Write($"Invalid password. Attempts: {attempts}/{maxAttempts} ");
global::System.Threading.Thread.Sleep(1000);
return false;
}
loginAttempts.Remove(username.ToLower());
CMLeonOS.UI.TUIHelper.SetColors(global::System.ConsoleColor.Green, global::System.ConsoleColor.Black);
global::System.Console.SetCursorPosition(17, 24);
global::System.Console.Write("Login successful! ");

View File

@@ -329,6 +329,60 @@ nano <file>
nano myfile.txt
```
### hex
使用16进制编辑器编辑二进制文件。
**用法:**
```bash
hex <filename>
```
**示例:**
```bash
hex test.bin
hex kernel.sys
```
**控制键:**
- `↑ ↓ ← →` - 移动光标
- `Page Up / Page Down` - 滚动视图
- `0-9, A-F` - 编辑字节值
- `S` - 保存文件
- `Q` - 退出编辑器
**说明:**
- 显示文件的16进制字节值和对应的ASCII字符
- 每行显示16个字节分为8个字节一组
- 显示每行的偏移地址8位16进制
- 光标位置用白色背景高亮显示
- 文件修改后显示 [MODIFIED] 标记
- 支持查看和编辑任意大小的二进制文件
- 按 S 键保存修改到文件
- 按 Q 键退出编辑器(不保存修改)
**界面示例:**
```
====================================
Hex Editor
====================================
File: test.bin
Size: 256 bytes [MODIFIED]
00000000 48 65 6C 6C 6F 20 57 6F 72 6C 64 21 00 00 00 00 |Hello World.....|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
Cursor: 0x00000000 (0)
Value: 0x48
Controls:
Arrow Keys - Move cursor
Page Up/Down - Scroll view
0-9, A-F - Edit byte
S - Save file
Q - Quit
```
## 用户管理命令
### user
@@ -498,6 +552,41 @@ lua <file>
lua script.lua
```
### lua2cla
将 Lua 文件转换为 CMLeonOS Lua 应用格式(.cla
**用法:**
```bash
lua2cla <lua_file>
```
**示例:**
```bash
lua2cla app.lua
```
**说明:**
- 文件头为 `CMLeonOS_CLA`
- 转换后的文件可以通过 `cla` 命令运行
### cla
运行 CMLeonOS Lua 应用格式(.cla文件。
**用法:**
```bash
cla <cla_file>
```
**示例:**
```bash
cla app.cla
```
**说明:**
- 运行 .cla 格式的加密 Lua 应用
- 自动解密并执行 Lua 代码
- 文件头必须为 `CMLeonOS_CLA`
### com
执行命令脚本文件。
@@ -636,7 +725,7 @@ app list # 列出所有可用应用
app install <name> # 安装应用
app uninstall <name> # 卸载应用
app installed # 列出已安装应用
app help # 显示帮助信息
app help # 显示帮助信息
```
**示例:**
@@ -777,6 +866,14 @@ shutdown
cuitest
```
### testtui
测试 TUI 框架。
**用法:**
```bash
testtui
```
### testgui
测试图形界面。
@@ -812,8 +909,8 @@ snake
**说明:**
- 使用方向键 (↑ ↓ ← →) 控制蛇的移动
- 按 ESC 或 Q 键退出游戏
- 蛇身用绿色 表示
- 食物用红色 表示
- 蛇身用绿色 # 表示
- 食物用红色 O 表示
- 吃到食物得分 +10 分
- 撞到墙壁或自己身体游戏结束
- 游戏区域40x20 字符

View File

@@ -1,9 +1,73 @@
using System;
using System.Collections.Generic;
using System.IO;
using UniLua;
namespace CMLeonOS
{
public class NanoSettings
{
public bool EnableSmartIndent { get; set; } = true;
public bool EnableAutoCompleteBrackets { get; set; } = true;
public bool EnableAutoCompleteQuotes { get; set; } = true;
public bool EnableSmartDelete { get; set; } = true;
public bool EnableSyntaxHighlight { get; set; } = true;
public void Save(string filePath)
{
try
{
bool smartIndent = EnableSmartIndent;
bool autoBrackets = EnableAutoCompleteBrackets;
bool autoQuotes = EnableAutoCompleteQuotes;
bool smartDelete = EnableSmartDelete;
bool syntaxHighlight = EnableSyntaxHighlight;
string content = $"{smartIndent},{autoBrackets},{autoQuotes},{smartDelete},{syntaxHighlight}";
using (StreamWriter sw = new StreamWriter(filePath))
{
sw.Write(content);
}
}
catch
{
}
}
public void Load(string filePath)
{
try
{
if (File.Exists(filePath))
{
using (StreamReader sr = new StreamReader(filePath))
{
string content = sr.ReadToEnd();
string[] parts = content.Split(',');
if (parts.Length >= 5)
{
bool smartIndent, autoBrackets, autoQuotes, smartDelete, syntaxHighlight;
bool.TryParse(parts[0], out smartIndent);
bool.TryParse(parts[1], out autoBrackets);
bool.TryParse(parts[2], out autoQuotes);
bool.TryParse(parts[3], out smartDelete);
bool.TryParse(parts[4], out syntaxHighlight);
EnableSmartIndent = smartIndent;
EnableAutoCompleteBrackets = autoBrackets;
EnableAutoCompleteQuotes = autoQuotes;
EnableSmartDelete = smartDelete;
EnableSyntaxHighlight = syntaxHighlight;
}
}
}
}
catch
{
}
}
}
public class Nano
{
private string path;
@@ -22,6 +86,7 @@ namespace CMLeonOS
private FileSystem fileSystem;
private UserSystem userSystem;
private Shell shell;
private NanoSettings settings = new NanoSettings();
private readonly (string, string)[] SHORTCUTS = new (string, string)[]
{
@@ -47,15 +112,22 @@ namespace CMLeonOS
if (value != null && fileSystem != null)
{
string fullPath = fileSystem.GetFullPath(value);
if (System.IO.File.Exists(fullPath))
try
{
string fullPath = fileSystem.GetFullPath(value);
string text = fileSystem.ReadFile(fullPath);
text = text.Replace("\r\n", "\n");
lines.AddRange(text.Split('\n'));
if (!string.IsNullOrEmpty(text))
{
text = text.Replace("\r\n", "\n");
lines.AddRange(text.Split('\n'));
}
else
{
lines.Add(string.Empty);
}
}
else
catch
{
lines.Add(string.Empty);
}
@@ -90,7 +162,6 @@ namespace CMLeonOS
{
int y = i - scrollY + TITLEBAR_HEIGHT;
if (y < TITLEBAR_HEIGHT || y >= consoleHeight - SHORTCUT_BAR_HEIGHT) continue;
Console.SetCursorPosition(0, y);
if (i >= lines.Count || scrollX >= lines[i].Length)
@@ -100,7 +171,15 @@ namespace CMLeonOS
else
{
string line = lines[i].Substring(scrollX, Math.Min(consoleWidth, lines[i].Length - scrollX));
Console.Write(line + new string(' ', Math.Max(0, consoleWidth - line.Length)));
if (IsLuaFile() && settings.EnableSyntaxHighlight)
{
RenderLuaLine(line, consoleWidth);
}
else
{
Console.Write(line + new string(' ', Math.Max(0, consoleWidth - line.Length)));
}
}
}
@@ -111,34 +190,410 @@ namespace CMLeonOS
Console.SetCursorPosition(linePos - scrollX, currentLine + TITLEBAR_HEIGHT - scrollY);
}
private bool IsLuaFile()
{
if (path != null)
{
string extension = System.IO.Path.GetExtension(path)?.ToLower();
return extension == ".lua";
}
return false;
}
private void RenderLuaLine(string line, int consoleWidth)
{
int pos = 0;
bool inString = false;
bool inComment = false;
bool inLongComment = false;
char stringDelimiter = '\0';
while (pos < line.Length && pos < consoleWidth)
{
if (inComment)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write(line[pos]);
pos++;
}
else if (inLongComment)
{
Console.ForegroundColor = ConsoleColor.Green;
if (pos + 1 < line.Length && line[pos] == ']' && line[pos + 1] == ']')
{
inLongComment = false;
Console.Write(line[pos]);
pos++;
Console.Write(line[pos]);
pos++;
}
else
{
Console.Write(line[pos]);
pos++;
}
}
else if (pos + 1 < line.Length && line[pos] == '-' && line[pos + 1] == '-')
{
if (pos + 3 < line.Length && line[pos + 2] == '[' && line[pos + 3] == '[')
{
inLongComment = true;
Console.ForegroundColor = ConsoleColor.Green;
Console.Write(line.Substring(pos));
break;
}
else
{
inComment = true;
Console.ForegroundColor = ConsoleColor.Green;
Console.Write(line.Substring(pos));
break;
}
}
else if (inString)
{
Console.ForegroundColor = ConsoleColor.Yellow;
if (line[pos] == stringDelimiter)
{
if (pos + 1 < line.Length && line[pos + 1] == stringDelimiter)
{
Console.Write(line[pos]);
pos++;
Console.Write(line[pos]);
pos++;
}
else
{
Console.Write(line[pos]);
inString = false;
pos++;
}
}
else if (line[pos] == '\\')
{
Console.Write(line[pos]);
pos++;
if (pos < line.Length)
{
Console.Write(line[pos]);
pos++;
}
}
else
{
Console.Write(line[pos]);
pos++;
}
}
else
{
if (line[pos] == '"' || line[pos] == '\'')
{
inString = true;
stringDelimiter = line[pos];
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write(line[pos]);
pos++;
}
else if (IsLuaNumber(line, pos))
{
Console.ForegroundColor = ConsoleColor.Magenta;
while (pos < line.Length && IsLuaNumber(line, pos))
{
Console.Write(line[pos]);
pos++;
}
}
else if (IsLuaOperator(line, pos))
{
Console.ForegroundColor = ConsoleColor.DarkYellow;
if (pos + 1 < line.Length && IsLuaOperator(line, pos + 1))
{
Console.Write(line[pos]);
pos++;
Console.Write(line[pos]);
pos++;
}
else
{
Console.Write(line[pos]);
pos++;
}
}
else if (IsLuaKeyword(line, pos))
{
Console.ForegroundColor = ConsoleColor.Cyan;
string keyword = GetLuaKeyword(line, pos);
Console.Write(keyword);
pos += keyword.Length;
}
else if (IsLuaBuiltin(line, pos))
{
Console.ForegroundColor = ConsoleColor.DarkCyan;
string builtin = GetLuaBuiltin(line, pos);
Console.Write(builtin);
pos += builtin.Length;
}
else if (IsLuaFunctionCall(line, pos))
{
Console.ForegroundColor = ConsoleColor.DarkMagenta;
string funcName = GetLuaFunctionName(line, pos);
Console.Write(funcName);
pos += funcName.Length;
}
else
{
Console.ForegroundColor = ConsoleColor.White;
Console.Write(line[pos]);
pos++;
}
}
}
if (pos < consoleWidth)
{
Console.Write(new string(' ', consoleWidth - pos));
}
Console.ResetColor();
}
private bool IsLuaNumber(string line, int pos)
{
if (pos >= line.Length) return false;
char c = line[pos];
if (!char.IsDigit(c) && c != '.') return false;
if (c == '.')
{
if (pos + 1 >= line.Length) return false;
return char.IsDigit(line[pos + 1]);
}
return true;
}
private bool IsLuaOperator(string line, int pos)
{
if (pos >= line.Length) return false;
char c = line[pos];
return c == '+' || c == '-' || c == '*' || c == '/' || c == '^' ||
c == '%' || c == '#' || c == '=' || c == '~' ||
c == '<' || c == '>' || c == '&' || c == '|' ||
c == '(' || c == ')' || c == '[' || c == ']' ||
c == '{' || c == '}' || c == ',' || c == ';';
}
private bool IsLuaKeyword(string line, int pos)
{
string[] keywords = {
"function", "end", "if", "then", "else", "elseif", "while", "do",
"for", "return", "local", "true", "false", "nil", "and", "or",
"not", "break", "repeat", "until", "in", "goto", "self"
};
foreach (string keyword in keywords)
{
if (pos + keyword.Length <= line.Length && line.Substring(pos, keyword.Length) == keyword)
{
char prevChar = pos > 0 ? line[pos - 1] : ' ';
char nextChar = pos + keyword.Length < line.Length ? line[pos + keyword.Length] : ' ';
if (!char.IsLetterOrDigit(prevChar) && !char.IsLetterOrDigit(nextChar) && prevChar != '_' && nextChar != '_')
{
return true;
}
}
}
return false;
}
private string GetLuaKeyword(string line, int pos)
{
string[] keywords = {
"function", "end", "if", "then", "else", "elseif", "while", "do",
"for", "return", "local", "true", "false", "nil", "and", "or",
"not", "break", "repeat", "until", "in", "goto", "self"
};
foreach (string keyword in keywords)
{
if (pos + keyword.Length <= line.Length && line.Substring(pos, keyword.Length) == keyword)
{
char prevChar = pos > 0 ? line[pos - 1] : ' ';
char nextChar = pos + keyword.Length < line.Length ? line[pos + keyword.Length] : ' ';
if (!char.IsLetterOrDigit(prevChar) && !char.IsLetterOrDigit(nextChar) && prevChar != '_' && nextChar != '_')
{
return keyword;
}
}
}
return "";
}
private bool IsLuaBuiltin(string line, int pos)
{
string[] builtins = {
"print", "type", "tonumber", "tostring", "pairs", "ipairs",
"next", "select", "unpack", "assert", "error", "pcall",
"xpcall", "load", "loadstring", "loadfile", "dofile",
"require", "setmetatable", "getmetatable", "rawget", "rawset",
"rawequal", "rawlen", "gcinfo", "collectgarbage", "newproxy"
};
foreach (string builtin in builtins)
{
if (pos + builtin.Length <= line.Length && line.Substring(pos, builtin.Length) == builtin)
{
char prevChar = pos > 0 ? line[pos - 1] : ' ';
char nextChar = pos + builtin.Length < line.Length ? line[pos + builtin.Length] : ' ';
if (!char.IsLetterOrDigit(prevChar) && !char.IsLetterOrDigit(nextChar) && prevChar != '_' && nextChar != '_')
{
return true;
}
}
}
return false;
}
private string GetLuaBuiltin(string line, int pos)
{
string[] builtins = {
"print", "type", "tonumber", "tostring", "pairs", "ipairs",
"next", "select", "unpack", "assert", "error", "pcall",
"xpcall", "load", "loadstring", "loadfile", "dofile",
"require", "setmetatable", "getmetatable", "rawget", "rawset",
"rawequal", "rawlen", "gcinfo", "collectgarbage", "newproxy"
};
foreach (string builtin in builtins)
{
if (pos + builtin.Length <= line.Length && line.Substring(pos, builtin.Length) == builtin)
{
char prevChar = pos > 0 ? line[pos - 1] : ' ';
char nextChar = pos + builtin.Length < line.Length ? line[pos + builtin.Length] : ' ';
if (!char.IsLetterOrDigit(prevChar) && !char.IsLetterOrDigit(nextChar) && prevChar != '_' && nextChar != '_')
{
return builtin;
}
}
}
return "";
}
private bool IsLuaFunctionCall(string line, int pos)
{
if (pos >= line.Length || !char.IsLetter(line[pos]) && line[pos] != '_') return false;
int endPos = pos;
while (endPos < line.Length && (char.IsLetterOrDigit(line[endPos]) || line[endPos] == '_'))
{
endPos++;
}
if (endPos < line.Length && line[endPos] == '(')
{
return true;
}
return false;
}
private string GetLuaFunctionName(string line, int pos)
{
int endPos = pos;
while (endPos < line.Length && (char.IsLetterOrDigit(line[endPos]) || line[endPos] == '_'))
{
endPos++;
}
return line.Substring(pos, endPos - pos);
}
// Insert a new line at the cursor.
private void InsertLine()
{
string line = lines[currentLine];
if (linePos == line.Length)
if (IsLuaFile() && settings.EnableSmartIndent)
{
lines.Insert(currentLine + 1, string.Empty);
string currentIndent = GetLineIndent(line);
if (linePos == line.Length)
{
lines.Insert(currentLine + 1, currentIndent);
}
else
{
lines.Insert(currentLine + 1, currentIndent + line.Substring(linePos, line.Length - linePos));
lines[currentLine] = line.Remove(linePos, line.Length - linePos);
}
if (line.TrimEnd().EndsWith("then") || line.TrimEnd().EndsWith("do") || line.TrimEnd().EndsWith("else") || line.TrimEnd().EndsWith("elseif") || line.TrimEnd().EndsWith("repeat"))
{
lines[currentLine + 1] = lines[currentLine + 1] + " ";
}
}
else
{
lines.Insert(currentLine + 1, line.Substring(linePos, line.Length - linePos));
lines[currentLine] = line.Remove(linePos, line.Length - linePos);
if (linePos == line.Length)
{
lines.Insert(currentLine + 1, string.Empty);
}
else
{
lines.Insert(currentLine + 1, line.Substring(linePos, line.Length - linePos));
lines[currentLine] = line.Remove(linePos, line.Length - linePos);
}
}
updatedLinesStart = currentLine;
updatedLinesEnd = lines.Count - 1;
currentLine += 1;
linePos = 0;
linePos = lines[currentLine].Length;
modified = true;
}
private string GetLineIndent(string line)
{
int indent = 0;
foreach (char c in line)
{
if (c == ' ')
{
indent++;
}
else if (c == '\t')
{
indent += 4;
}
else
{
break;
}
}
return new string(' ', indent);
}
// Insert text at the cursor.
private void Insert(string text)
{
for (int i = 0; i < text.Length; i++)
{
lines[currentLine] = lines[currentLine].Insert(linePos, text[i].ToString());
char c = text[i];
if (IsLuaFile())
{
c = HandleLuaAutoComplete(c);
}
lines[currentLine] = lines[currentLine].Insert(linePos, c.ToString());
linePos++;
updatedLinesStart = currentLine;
@@ -147,6 +602,54 @@ namespace CMLeonOS
modified = true;
}
private char HandleLuaAutoComplete(char c)
{
string line = lines[currentLine];
if (settings.EnableAutoCompleteBrackets)
{
if (c == '(')
{
lines[currentLine] = lines[currentLine].Insert(linePos, ")");
return '(';
}
else if (c == '[')
{
lines[currentLine] = lines[currentLine].Insert(linePos, "]");
return '[';
}
else if (c == '{')
{
lines[currentLine] = lines[currentLine].Insert(linePos, "}");
return '{';
}
}
if (settings.EnableAutoCompleteQuotes)
{
if (c == '"')
{
if (linePos > 0 && line[linePos - 1] == '\\')
{
return '"';
}
lines[currentLine] = lines[currentLine].Insert(linePos, "\"");
return '"';
}
else if (c == '\'')
{
if (linePos > 0 && line[linePos - 1] == '\\')
{
return '\'';
}
lines[currentLine] = lines[currentLine].Insert(linePos, "'");
return '\'';
}
}
return c;
}
private void InsertTab()
{
Insert(" ");
@@ -169,6 +672,17 @@ namespace CMLeonOS
}
else
{
if (IsLuaFile() && settings.EnableSmartDelete)
{
string line = lines[currentLine];
char charToDelete = line[linePos - 1];
if (linePos < line.Length && IsMatchingPair(charToDelete, line[linePos]))
{
lines[currentLine] = lines[currentLine].Remove(linePos, 1);
}
}
lines[currentLine] = lines[currentLine].Remove(linePos - 1, 1);
linePos--;
@@ -178,6 +692,15 @@ namespace CMLeonOS
modified = true;
}
private bool IsMatchingPair(char open, char close)
{
return (open == '(' && close == ')') ||
(open == '[' && close == ']') ||
(open == '{' && close == '}') ||
(open == '"' && close == '"') ||
(open == '\'' && close == '\'');
}
// Move the cursor left.
private void MoveLeft()
{
@@ -702,6 +1225,9 @@ namespace CMLeonOS
}
switch (key.Key)
{
case ConsoleKey.F2:
ShowSettingsMenu();
return true;
case ConsoleKey.Tab:
InsertTab();
break;
@@ -807,12 +1333,163 @@ namespace CMLeonOS
RenderShortcuts(SHORTCUTS);
}
private void ShowSettingsMenu()
{
Console.BackgroundColor = ConsoleColor.Blue;
Console.ForegroundColor = ConsoleColor.White;
Console.Clear();
int consoleWidth = 80;
int consoleHeight = 25;
string title = " Nano Settings";
string[] options = new string[]
{
"1. Smart Indent",
"2. Auto Complete Brackets",
"3. Auto Complete Quotes",
"4. Smart Delete",
"5. Syntax Highlight",
"6. Save and Exit"
};
int maxOptionLength = 0;
foreach (string option in options)
{
if (option.Length > maxOptionLength)
{
maxOptionLength = option.Length;
}
}
int menuWidth = maxOptionLength + 10;
int menuHeight = options.Length + 4;
int menuX = (consoleWidth - menuWidth) / 2;
int menuY = (consoleHeight - menuHeight) / 2;
int titleX = menuX + (menuWidth - title.Length) / 2;
Console.SetCursorPosition(titleX, menuY);
Console.Write(title);
int borderLeft = menuX;
int borderRight = menuX + menuWidth - 1;
int borderTop = menuY;
int borderBottom = menuY + menuHeight - 1;
for (int i = 0; i < menuWidth; i++)
{
Console.SetCursorPosition(borderLeft + i, borderTop);
Console.Write("-");
}
for (int i = 0; i < menuHeight; i++)
{
Console.SetCursorPosition(borderLeft, borderTop + 1 + i);
Console.Write("|");
Console.SetCursorPosition(borderRight, borderTop + 1 + i);
Console.Write("|");
}
for (int i = 0; i < menuWidth; i++)
{
Console.SetCursorPosition(borderLeft + i, borderBottom);
Console.Write("-");
}
for (int i = 0; i < options.Length; i++)
{
int optionY = borderTop + 2 + i;
Console.SetCursorPosition(borderLeft + 2, optionY);
Console.Write(options[i]);
string status = GetSettingStatus(i);
int statusX = borderRight - status.Length - 2;
Console.SetCursorPosition(statusX, optionY);
Console.Write($"[{status}]");
}
int promptY = borderBottom - 2;
string prompt = "Use 1-6 to toggle, ESC to exit";
int promptX = menuX + (menuWidth - prompt.Length) / 2;
Console.SetCursorPosition(promptX, promptY);
Console.Write(prompt);
while (true)
{
ConsoleKeyInfo key = Console.ReadKey(true);
if (key.Key == ConsoleKey.Escape)
{
break;
}
else if (key.KeyChar >= '1' && key.KeyChar <= '6')
{
int option = key.KeyChar - '1';
ToggleSetting(option);
ShowSettingsMenu();
break;
}
}
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.White;
Console.Clear();
RenderUI();
updatedLinesStart = 0;
updatedLinesEnd = lines.Count - 1;
}
private string GetSettingStatus(int option)
{
switch (option)
{
case 0:
return settings.EnableSmartIndent ? "ON " : "OFF";
case 1:
return settings.EnableAutoCompleteBrackets ? "ON " : "OFF";
case 2:
return settings.EnableAutoCompleteQuotes ? "ON " : "OFF";
case 3:
return settings.EnableSmartDelete ? "ON " : "OFF";
case 4:
return settings.EnableSyntaxHighlight ? "ON " : "OFF";
default:
return "";
}
}
private void ToggleSetting(int option)
{
switch (option)
{
case 0:
settings.EnableSmartIndent = !settings.EnableSmartIndent;
break;
case 1:
settings.EnableAutoCompleteBrackets = !settings.EnableAutoCompleteBrackets;
break;
case 2:
settings.EnableAutoCompleteQuotes = !settings.EnableAutoCompleteQuotes;
break;
case 3:
settings.EnableSmartDelete = !settings.EnableSmartDelete;
break;
case 4:
settings.EnableSyntaxHighlight = !settings.EnableSyntaxHighlight;
break;
case 5:
break;
}
}
public void Start()
{
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.White;
Console.Clear();
settings.Load(@"0:\system\nano.dat");
RenderUI();
while (!quit)
{
@@ -826,6 +1503,8 @@ namespace CMLeonOS
HandleInput();
UpdateScrolling();
}
settings.Save(@"0:\system\nano.dat");
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.White;

View File

@@ -118,7 +118,7 @@ namespace UniLua
return 1;
}
CMLeonOS.Kernel.shell?.ExecuteCommand(command);
CMLeonOS.Kernel.ExecuteCommand(command);
lua.PushBoolean(true);
return 1;
}
@@ -132,7 +132,7 @@ namespace UniLua
return 1;
}
CMLeonOS.Kernel.shell?.ExecuteCommand($"com {filePath}");
CMLeonOS.Kernel.ExecuteCommand($"com {filePath}");
lua.PushBoolean(true);
return 1;
}

View File

@@ -163,6 +163,12 @@ namespace CMLeonOS.shell
case "uptime":
shell.ShowUptime();
break;
case "ps":
shell.ShowProcesses();
break;
case "kill":
shell.KillProcess(args);
break;
case "grep":
shell.GrepFile(args);
break;
@@ -190,6 +196,12 @@ namespace CMLeonOS.shell
case "lua":
shell.ExecuteLuaScript(args);
break;
case "lua2cla":
shell.ConvertLuaToCla(args);
break;
case "cla":
shell.RunClaFile(args);
break;
case "testgui":
shell.ProcessTestGui();
break;
@@ -202,6 +214,9 @@ namespace CMLeonOS.shell
case "snake":
shell.PlaySnake();
break;
case "hex":
shell.EditHexFile(args);
break;
case "alias":
shell.ProcessAlias(args);
break;

View File

@@ -14,8 +14,8 @@ namespace CMLeonOS.Commands.Editor
try
{
var editor = new CMLeonOS.Editor(fileName, fileSystem);
editor.Run();
var nano = new CMLeonOS.Nano(fileName, true, fileSystem);
nano.Start();
}
catch (Exception ex)
{

View File

@@ -260,6 +260,18 @@ namespace CMLeonOS.Commands
Description = "Show system uptime"
},
new CommandInfo
{
Command = "ps",
Parameters = "",
Description = "List all running processes"
},
new CommandInfo
{
Command = "kill",
Parameters = "<process_id>",
Description = "Kill a process by ID"
},
new CommandInfo
{
Command = "matrix",
Parameters = "",
@@ -284,6 +296,12 @@ namespace CMLeonOS.Commands
Description = "Search text in file"
},
new CommandInfo
{
Command = "hex",
Parameters = "<filename>",
Description = "Hexadecimal file editor"
},
new CommandInfo
{
Command = "ping",
Parameters = "<ip>",
@@ -369,6 +387,18 @@ namespace CMLeonOS.Commands
Description = "Execute Lua script"
},
new CommandInfo
{
Command = "lua2cla",
Parameters = "<lua_file>",
Description = "Convert Lua to CLA format"
},
new CommandInfo
{
Command = "cla",
Parameters = "<cla_file>",
Description = "Run CLA application"
},
new CommandInfo
{
Command = "version",
Parameters = "",
@@ -391,7 +421,7 @@ namespace CMLeonOS.Commands
{
Command = "help",
Parameters = "<page>",
Description = "Show help page (1-3)",
Description = "Show help page (1-5)",
SubCommands = new[] { new SubCommandInfo { Command = "help all", Description = "Show all help pages" } }
}
};
@@ -471,24 +501,32 @@ namespace CMLeonOS.Commands
pageNumber = 1;
}
int startIndex = (pageNumber - 1) * CommandsPerPage;
int endIndex = Math.Min(startIndex + CommandsPerPage, allCommands.Count);
Console.WriteLine("====================================");
Console.WriteLine($" Help - Page {pageNumber}/{totalPages}");
Console.WriteLine("====================================");
Console.WriteLine();
int linesOnPage = 0;
for (int i = startIndex; i < endIndex; i++)
int currentLine = 0;
for (int i = 0; i < allCommands.Count; i++)
{
int cmdLines = GetCommandLinesCount(allCommands[i]);
if (linesOnPage + cmdLines > CommandsPerPage)
if (currentLine + cmdLines <= (pageNumber - 1) * CommandsPerPage)
{
currentLine += cmdLines;
continue;
}
if (linesOnPage >= CommandsPerPage)
{
break;
}
DisplayCommand(allCommands[i]);
linesOnPage += cmdLines;
currentLine += cmdLines;
}
if (pageNumber < totalPages)

View File

@@ -7,7 +7,7 @@ namespace CMLeonOS.Commands
public static void ProcessAbout()
{
Console.WriteLine("CMLeonOS Project");
Console.WriteLine("By LeonOS 2 Developement Team");
Console.WriteLine("By LeonOS 2 Developer Team");
}
}
}

View File

@@ -0,0 +1,82 @@
using System;
using System.IO;
using System.Text;
using UniLua;
namespace CMLeonOS.Commands.Script
{
public static class ClaCommand
{
private const string FILE_HEADER = "CMLeonOS_CLA";
private static readonly byte[] ENCRYPTION_KEY = { 0x55, 0xAA, 0x33, 0xCC, 0x77, 0x88, 0x11, 0x22, 0x44, 0x66, 0x99, 0xBB };
public static void RunClaFile(string args, CMLeonOS.FileSystem fileSystem, Shell shell, Action<string> showError, Action<string> showWarning)
{
if (string.IsNullOrEmpty(args))
{
showError(UsageGenerator.GenerateSimpleUsage("cla", "<cla_file>"));
showError("Example: cla app.cla");
return;
}
string claFilePath = fileSystem.GetFullPath(args);
if (!File.Exists(claFilePath))
{
showError($"Error: CLA file not found: {args}");
return;
}
if (!claFilePath.EndsWith(".cla", StringComparison.OrdinalIgnoreCase))
{
showError("Error: Input file must have .cla extension");
return;
}
try
{
string luaContent = DecryptClaFile(claFilePath);
if (string.IsNullOrEmpty(luaContent))
{
showError("Error: Failed to decrypt CLA file or file is corrupted");
return;
}
LuaCommand.ExecuteLuaCode(luaContent, fileSystem, shell, showError, showWarning);
}
catch (Exception ex)
{
showError($"Error running CLA file: {ex.Message}");
}
}
private static string DecryptClaFile(string claFilePath)
{
using (BinaryReader reader = new BinaryReader(File.OpenRead(claFilePath)))
{
byte[] headerBytes = reader.ReadBytes(FILE_HEADER.Length);
string header = Encoding.ASCII.GetString(headerBytes);
if (header != FILE_HEADER)
{
throw new Exception("Invalid CLA file format: Missing or incorrect header");
}
byte[] encryptedData = reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position));
return DecryptData(encryptedData);
}
}
private static string DecryptData(byte[] data)
{
for (int i = 0; i < data.Length; i++)
{
int keyIndex = i % ENCRYPTION_KEY.Length;
data[i] = (byte)(data[i] ^ ENCRYPTION_KEY[keyIndex]);
}
return Encoding.UTF8.GetString(data);
}
}
}

View File

@@ -0,0 +1,70 @@
using System;
using System.IO;
using System.Text;
namespace CMLeonOS.Commands.Script
{
public static class Lua2ClaCommand
{
private const string FILE_HEADER = "CMLeonOS_CLA";
private static readonly byte[] ENCRYPTION_KEY = { 0x55, 0xAA, 0x33, 0xCC, 0x77, 0x88, 0x11, 0x22, 0x44, 0x66, 0x99, 0xBB };
public static void ConvertLuaToCla(string args, CMLeonOS.FileSystem fileSystem, Action<string> showError, Action<string> showSuccess)
{
if (string.IsNullOrEmpty(args))
{
showError(UsageGenerator.GenerateSimpleUsage("lua2cla", "<lua_file>"));
showError("Example: lua2cla app.lua");
return;
}
string luaFilePath = fileSystem.GetFullPath(args);
if (!File.Exists(luaFilePath))
{
showError($"Error: Lua file not found: {args}");
return;
}
if (!luaFilePath.EndsWith(".lua", StringComparison.OrdinalIgnoreCase))
{
showError("Error: Input file must have .lua extension");
return;
}
try
{
string luaContent = File.ReadAllText(luaFilePath);
byte[] encryptedData = EncryptData(luaContent);
string claFilePath = luaFilePath.Substring(0, luaFilePath.Length - 4) + ".cla";
using (BinaryWriter writer = new BinaryWriter(File.Create(claFilePath)))
{
writer.Write(Encoding.ASCII.GetBytes(FILE_HEADER));
writer.Write(encryptedData);
}
showSuccess($"Successfully converted: {args} -> {Path.GetFileName(claFilePath)}");
Console.WriteLine($"Output file: {claFilePath}");
}
catch (Exception ex)
{
showError($"Error converting file: {ex.Message}");
}
}
private static byte[] EncryptData(string content)
{
byte[] data = Encoding.UTF8.GetBytes(content);
for (int i = 0; i < data.Length; i++)
{
int keyIndex = i % ENCRYPTION_KEY.Length;
data[i] = (byte)(data[i] ^ ENCRYPTION_KEY[keyIndex]);
}
return data;
}
}
}

View File

@@ -116,6 +116,60 @@ namespace CMLeonOS.Commands.Script
}
}
public static void ExecuteLuaCode(string code, CMLeonOS.FileSystem fileSystem, Shell shell, Action<string> showError, Action<string> showWarning)
{
if (string.IsNullOrWhiteSpace(code))
{
showWarning("Lua code is empty");
return;
}
try
{
ILuaState lua = LuaAPI.NewState();
lua.L_OpenLibs();
UniLua.ThreadStatus loadResult = lua.L_LoadString(code);
if (loadResult == UniLua.ThreadStatus.LUA_OK)
{
UniLua.ThreadStatus callResult = lua.PCall(0, 0, 0);
if (callResult == UniLua.ThreadStatus.LUA_OK)
{
}
else
{
string errorMsg = lua.ToString(-1);
if (string.IsNullOrWhiteSpace(errorMsg))
{
showError($"Script execution error: Unknown error");
}
else
{
showError($"Script execution error: {errorMsg}");
}
}
}
else
{
string errorMsg = lua.ToString(-1);
if (string.IsNullOrWhiteSpace(errorMsg))
{
showError($"Script load error: Unknown error");
}
else
{
showError($"Script load error: {errorMsg}");
}
}
}
catch (Exception ex)
{
showError($"Lua execution error: {ex.Message}");
}
}
private static void EnterLuaShell(Action<string> showError)
{
Console.WriteLine("====================================");

View File

@@ -0,0 +1,57 @@
using System;
namespace CMLeonOS.Commands.System
{
public static class KillCommand
{
public static void KillProcess(string args, Action<string> showError, Action<string> showWarning)
{
try
{
if (string.IsNullOrWhiteSpace(args))
{
showError("Usage: kill <process_id>");
showError("Example: kill 123");
return;
}
if (!ulong.TryParse(args, out ulong processId))
{
showError($"Invalid process ID: {args}");
showError("Process ID must be a number.");
return;
}
Process process = ProcessManager.GetProcessById(processId);
if (process == null)
{
showError($"Process not found: {processId}");
showError("Use 'ps' command to list all processes.");
return;
}
if (process.Name == "Shell")
{
showError("Cannot kill Shell process.");
showError("Use 'exit' command instead.");
return;
}
if (!process.IsRunning)
{
showWarning($"Process {process.Name} ({processId}) is already stopped.");
return;
}
CMLeonOS.Logger.Logger.Instance.Info("Kill", $"Killing process: {process.Name} ({processId})");
process.TryStop();
Console.WriteLine($"Process {process.Name} ({processId}) stopped successfully.");
}
catch (Exception ex)
{
showError($"Error killing process: {ex.Message}");
}
}
}
}

View File

@@ -0,0 +1,57 @@
using System;
namespace CMLeonOS.Commands.System
{
public static class PsCommand
{
public static void ShowProcesses(Action<string> showError, Action<string> showWarning)
{
try
{
Console.WriteLine("====================================");
Console.WriteLine(" Process List");
Console.WriteLine("====================================");
Console.WriteLine();
if (ProcessManager.Processes.Count == 0)
{
Console.WriteLine("No processes running.");
Console.WriteLine();
return;
}
Console.Write("ID ");
Console.Write("Name ");
Console.Write("Type ");
Console.Write("Parent ");
Console.WriteLine("Status ");
Console.WriteLine("----------------------------------------------------------------------");
foreach (var process in ProcessManager.Processes)
{
string parentId = process.Parent != null ? process.Parent.Id.ToString() : "N/A";
string status = process.IsRunning ? "Running" : "Stopped";
string type = process.Type.ToString();
Console.Write(process.Id.ToString().PadRight(8));
Console.Write(" ");
Console.Write(process.Name.PadRight(20));
Console.Write(" ");
Console.Write(type.PadRight(12));
Console.Write(" ");
Console.Write(parentId.PadRight(8));
Console.Write(" ");
Console.WriteLine(status);
}
Console.WriteLine();
Console.WriteLine("Total processes: " + ProcessManager.Processes.Count);
Console.WriteLine();
}
catch (Exception ex)
{
showError($"Error listing processes: {ex.Message}");
}
}
}
}

View File

@@ -58,6 +58,18 @@ namespace CMLeonOS.Commands
Console.WriteLine("Error: LoggerEnabled must be 'true' or 'false'");
}
}
else if (key.ToLower() == "maxloginattempts")
{
if (int.TryParse(value, out int attempts) && attempts > 0)
{
SettingsManager.MaxLoginAttempts = attempts;
Console.WriteLine($"MaxLoginAttempts set to {attempts}");
}
else
{
Console.WriteLine("Error: MaxLoginAttempts must be a positive integer");
}
}
else
{
SettingsManager.SetSetting(key, value);

View File

@@ -0,0 +1,49 @@
using System;
using System.IO;
namespace CMLeonOS.Commands.Utility
{
public static class HexCommand
{
public static void EditHexFile(string args)
{
try
{
if (string.IsNullOrWhiteSpace(args))
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Usage: hex <filename>");
Console.WriteLine("Example: hex test.bin");
Console.WriteLine();
Console.WriteLine("Controls:");
Console.WriteLine(" Arrow Keys - Move cursor");
Console.WriteLine(" Page Up/Down - Scroll view");
Console.WriteLine(" 0-9, A-F - Edit byte");
Console.WriteLine(" S - Save file");
Console.WriteLine(" Q - Quit");
Console.ResetColor();
return;
}
string filePath = args.Trim();
if (!File.Exists(filePath))
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"File not found: {filePath}");
Console.ResetColor();
return;
}
var editor = new HexEditor(filePath);
editor.Run();
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"Error opening hex editor: {ex.Message}");
Console.ResetColor();
}
}
}
}

View File

@@ -0,0 +1,258 @@
using System;
using System.IO;
namespace CMLeonOS.Commands.Utility
{
public class HexEditor
{
private byte[] data;
private int cursorPosition;
private int viewOffset;
private int bytesPerLine = 16;
private int bytesPerGroup = 2;
private string filePath;
private bool modified;
private bool running;
public HexEditor(string path)
{
filePath = path;
if (File.Exists(path))
{
data = File.ReadAllBytes(path);
}
else
{
data = new byte[256];
}
cursorPosition = 0;
viewOffset = 0;
modified = false;
running = true;
}
public void Run()
{
Console.Clear();
Console.WriteLine("====================================");
Console.WriteLine(" Hex Editor");
Console.WriteLine("====================================");
Console.WriteLine();
Console.WriteLine("File: " + filePath);
Console.WriteLine("Size: " + data.Length + " bytes");
Console.WriteLine();
Console.WriteLine("Controls:");
Console.WriteLine(" Arrow Keys - Move cursor");
Console.WriteLine(" Page Up/Down - Scroll view");
Console.WriteLine(" 0-9, A-F - Edit byte");
Console.WriteLine(" S - Save file");
Console.WriteLine(" Q - Quit");
Console.WriteLine();
Console.WriteLine("Press any key to continue...");
Console.ReadKey(true);
while (running)
{
Display();
HandleInput();
}
}
private void Display()
{
Console.Clear();
Console.WriteLine("====================================");
Console.WriteLine(" Hex Editor");
Console.WriteLine("====================================");
Console.WriteLine();
Console.WriteLine("File: " + filePath);
Console.WriteLine("Size: " + data.Length + " bytes");
if (modified)
{
Console.Write(" [MODIFIED]");
}
Console.WriteLine();
Console.WriteLine();
int lines = (int)Math.Ceiling((double)data.Length / bytesPerLine);
int startLine = viewOffset / bytesPerLine;
int endLine = Math.Min(startLine + 20, lines);
for (int line = startLine; line < endLine; line++)
{
int offset = line * bytesPerLine;
if (offset >= data.Length) break;
Console.Write(offset.ToString("X8") + " ");
for (int i = 0; i < bytesPerLine; i++)
{
int byteOffset = offset + i;
if (byteOffset >= data.Length)
{
Console.Write(" ");
}
else
{
byte b = data[byteOffset];
bool isCursor = (byteOffset == cursorPosition);
if (isCursor)
{
Console.BackgroundColor = ConsoleColor.White;
Console.ForegroundColor = ConsoleColor.Black;
}
Console.Write(b.ToString("X2") + " ");
if (isCursor)
{
Console.ResetColor();
}
if ((i + 1) % bytesPerGroup == 0)
{
Console.Write(" ");
}
}
}
Console.Write(" |");
for (int i = 0; i < bytesPerLine; i++)
{
int byteOffset = offset + i;
if (byteOffset >= data.Length)
{
Console.Write(" ");
}
else
{
byte b = data[byteOffset];
bool isCursor = (byteOffset == cursorPosition);
if (isCursor)
{
Console.BackgroundColor = ConsoleColor.White;
Console.ForegroundColor = ConsoleColor.Black;
}
char c = (b >= 32 && b <= 126) ? (char)b : '.';
Console.Write(c);
if (isCursor)
{
Console.ResetColor();
}
}
}
Console.WriteLine("|");
}
Console.WriteLine();
Console.WriteLine("Cursor: 0x" + cursorPosition.ToString("X8") + " (" + cursorPosition + ")");
Console.WriteLine("Value: 0x" + data[cursorPosition].ToString("X2"));
Console.WriteLine();
Console.WriteLine("Controls:");
Console.WriteLine(" Arrow Keys - Move cursor");
Console.WriteLine(" Page Up/Down - Scroll view");
Console.WriteLine(" 0-9, A-F - Edit byte");
Console.WriteLine(" S - Save file");
Console.WriteLine(" Q - Quit");
}
private void HandleInput()
{
var key = Console.ReadKey(true);
switch (key.Key)
{
case ConsoleKey.UpArrow:
cursorPosition = Math.Max(0, cursorPosition - bytesPerLine);
break;
case ConsoleKey.DownArrow:
cursorPosition = Math.Min(data.Length - 1, cursorPosition + bytesPerLine);
break;
case ConsoleKey.LeftArrow:
cursorPosition = Math.Max(0, cursorPosition - 1);
break;
case ConsoleKey.RightArrow:
cursorPosition = Math.Min(data.Length - 1, cursorPosition + 1);
break;
case ConsoleKey.PageUp:
viewOffset = Math.Max(0, viewOffset - (bytesPerLine * 20));
break;
case ConsoleKey.PageDown:
viewOffset = Math.Min(data.Length - 1, viewOffset + (bytesPerLine * 20));
break;
case ConsoleKey.D0:
case ConsoleKey.D1:
case ConsoleKey.D2:
case ConsoleKey.D3:
case ConsoleKey.D4:
case ConsoleKey.D5:
case ConsoleKey.D6:
case ConsoleKey.D7:
case ConsoleKey.D8:
case ConsoleKey.D9:
int digit = key.KeyChar - '0';
EditByte(digit);
break;
case ConsoleKey.A:
EditByte(10);
break;
case ConsoleKey.B:
EditByte(11);
break;
case ConsoleKey.C:
EditByte(12);
break;
case ConsoleKey.D:
EditByte(13);
break;
case ConsoleKey.E:
EditByte(14);
break;
case ConsoleKey.F:
EditByte(15);
break;
case ConsoleKey.S:
SaveFile();
break;
case ConsoleKey.Q:
running = false;
break;
}
}
private void EditByte(int value)
{
if (cursorPosition >= 0 && cursorPosition < data.Length)
{
data[cursorPosition] = (byte)value;
modified = true;
}
}
private void SaveFile()
{
try
{
File.WriteAllBytes(filePath, data);
modified = false;
Console.WriteLine();
Console.WriteLine("File saved successfully!");
Console.WriteLine("Press any key to continue...");
Console.ReadKey(true);
}
catch (Exception ex)
{
Console.WriteLine();
Console.WriteLine("Error saving file: " + ex.Message);
Console.WriteLine("Press any key to continue...");
Console.ReadKey(true);
}
}
}
}

View File

@@ -128,7 +128,7 @@ namespace CMLeonOS
{
var command = parts[0].Trim().ToLower();
var args = parts.Length > 1 ? string.Join(" ", parts, 1, parts.Length - 1).Trim() : "";
ProcessCommand(command, args);
ProcessCommandAsProcess(command, args);
}
}
@@ -407,9 +407,9 @@ namespace CMLeonOS
"rmdir", "cat", "version", "about", "head", "tail", "wc", "cp",
"mv", "rename", "touch", "find", "tree", "grep", "getdisk", "user",
"cpass", "hostname", "ipconfig", "setdns", "setgateway", "nslookup",
"ping", "wget", "ftp", "tcpserver", "tcpclient", "lua", "branswe",
"beep", "env", "whoami", "uptime", "alias",
"unalias", "base64", "testgui"
"ping", "wget", "ftp", "tcpserver", "tcpclient", "lua", "lua2cla", "cla",
"branswe", "beep", "env", "whoami", "uptime", "alias",
"unalias", "base64", "testgui", "ps", "kill", "hex"
};
}
@@ -462,6 +462,59 @@ namespace CMLeonOS
shell.CommandList.ProcessCommand(this, expandedCommand, expandedArgs);
}
public void ProcessCommandAsProcess(string command, string args)
{
string expandedCommand = command;
string expandedArgs = args;
if (command.StartsWith(":"))
{
string appName = command.Substring(1);
string appPath = "0:\\apps\\" + appName + ".lua";
if (System.IO.File.Exists(appPath))
{
Commands.Script.LuaCommand.ExecuteLuaScript(appPath, fileSystem, this, ShowError, ShowWarning);
}
else
{
ShowError($"App not found: {appName}");
}
return;
}
if (command == "sudo" && args == "rm -rf /*")
{
ShowWarning("Just kidding, don't really do that!");
ShowWarning("System is protected, root directory won't be deleted!");
return;
}
string aliasValue = Commands.AliasCommand.GetAlias(command);
if (aliasValue != null)
{
var aliasParts = aliasValue.Split(new char[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries);
if (aliasParts.Length > 0)
{
expandedCommand = aliasParts[0];
if (aliasParts.Length > 1)
{
expandedArgs = aliasParts[1] + (string.IsNullOrEmpty(args) ? "" : " " + args);
}
else
{
expandedArgs = args;
}
}
}
var commandProcess = new CommandProcess(expandedCommand, expandedArgs, this);
ProcessManager.AddProcess(commandProcess);
commandProcess.TryStart();
commandProcess.TryRun();
commandProcess.TryStop();
}
public void ProcessEcho(string args)
{
Commands.System.EchoCommand.ProcessEcho(args);
@@ -1003,6 +1056,21 @@ namespace CMLeonOS
Commands.System.UptimeCommand.ShowUptime(ShowError, ShowWarning);
}
public void ShowProcesses()
{
Commands.System.PsCommand.ShowProcesses(ShowError, ShowWarning);
}
public void KillProcess(string args)
{
Commands.System.KillCommand.KillProcess(args, ShowError, ShowWarning);
}
public void EditHexFile(string args)
{
Commands.Utility.HexCommand.EditHexFile(args);
}
public void CreateFTP()
{
Console.WriteLine("====================================");
@@ -1502,6 +1570,16 @@ namespace CMLeonOS
Commands.Script.LuaCommand.ExecuteLuaScript(args, fileSystem, this, ShowError, ShowWarning);
}
public void ConvertLuaToCla(string args)
{
Commands.Script.Lua2ClaCommand.ConvertLuaToCla(args, fileSystem, ShowError, ShowSuccess);
}
public void RunClaFile(string args)
{
Commands.Script.ClaCommand.RunClaFile(args, fileSystem, this, ShowError, ShowWarning);
}
public void ProcessTestGui()
{
Commands.TestGuiCommand.RunTestGui();