diff --git a/Kernel.cs b/Kernel.cs index 89f33eb..f6cb0e1 100644 --- a/Kernel.cs +++ b/Kernel.cs @@ -34,6 +34,8 @@ public class Kernel : Sys.Kernel Sys.Mouse.MouseManager.Initialize(); Sys.Mouse.MouseManager.SetScreenSize((int)canvas.Mode.Width, (int)canvas.Mode.Height); Sys.Keyboard.KeyboardManager.Initialize(); + + ProcessManager.SpawnProcess(); } protected override void Run() diff --git a/Processes/CliProcess.cs b/Processes/CliProcess.cs index 8e17677..2469687 100644 --- a/Processes/CliProcess.cs +++ b/Processes/CliProcess.cs @@ -11,6 +11,8 @@ internal class CliProcess() : Process("Cli") private bool commandRunning = false; + private CancellationTokenSource? commandCancellationTokenSource = null; + internal override void Start(string[] args) { Console.Clear(); @@ -23,10 +25,20 @@ internal class CliProcess() : Process("Cli") internal override async void Tick() { - while (Console.KeyAvailable && !commandRunning) + while (Console.KeyAvailable) { ConsoleKeyInfo key = Console.ReadKey(intercept: true); + if (commandRunning) + { + if (key.Key == ConsoleKey.C && key.Modifiers.HasFlag(ConsoleModifiers.Control) && commandCancellationTokenSource is not null) + { + await commandCancellationTokenSource.CancelAsync(); + } + + continue; + } + switch (key.Key) { case ConsoleKey.Enter: @@ -87,9 +99,10 @@ internal class CliProcess() : Process("Cli") return; } + commandCancellationTokenSource = new CancellationTokenSource(); commandRunning = true; - bool handled = await CommandManager.TryExecute(input, Console.WriteLine); + bool handled = await CommandManager.TryExecuteAsync(input, Console.WriteLine, commandCancellationTokenSource.Token); if (!handled) { @@ -97,5 +110,7 @@ internal class CliProcess() : Process("Cli") } commandRunning = false; + commandCancellationTokenSource.Dispose(); + commandCancellationTokenSource = null; } } \ No newline at end of file diff --git a/Processes/TerminalProcess.cs b/Processes/TerminalProcess.cs index 2fc7a0f..45afa8e 100644 --- a/Processes/TerminalProcess.cs +++ b/Processes/TerminalProcess.cs @@ -14,6 +14,8 @@ public class TerminalProcess() : Process("Terminal") private Window window = null!; private readonly List history = []; private int historyIndex = -1; + private bool commandRunning = false; + private CancellationTokenSource? commandCancellationTokenSource = null; private string currentInput = ""; private readonly List textLines = []; private readonly Lock textLinesLock = new(); @@ -49,6 +51,16 @@ public class TerminalProcess() : Process("Terminal") private async void HandleKey(KeyEvent keyEvent) { + if (commandRunning) + { + if (keyEvent.Key == ConsoleKeyEx.C && keyEvent.Modifiers.HasFlag(ConsoleModifiers.Control) && commandCancellationTokenSource is not null) + { + await commandCancellationTokenSource.CancelAsync(); + } + + return; + } + if (keyEvent.Key == ConsoleKeyEx.Enter) { string cmd = currentInput; @@ -72,16 +84,19 @@ public class TerminalProcess() : Process("Terminal") } else { - window.OnKeyEvent -= HandleKey; + commandCancellationTokenSource = new CancellationTokenSource(); + commandRunning = true; - bool handled = await CommandManager.TryExecute(cmd, PrintLine); + bool handled = await CommandManager.TryExecuteAsync(cmd, PrintLine, commandCancellationTokenSource.Token); if (!handled) { PrintLine($"\"{cmd}\" is not a command"); } - window.OnKeyEvent += HandleKey; + commandRunning = false; + commandCancellationTokenSource.Dispose(); + commandCancellationTokenSource = null; } historyIndex = CommandManager.GetCommandHistory().Count; diff --git a/UI/CLI/CommandManager.cs b/UI/CLI/CommandManager.cs index baa30a9..e6ec96f 100644 --- a/UI/CLI/CommandManager.cs +++ b/UI/CLI/CommandManager.cs @@ -29,7 +29,7 @@ public static class CommandManager return commandHistory; } - public static async Task TryExecute(string input, Action printLine) + public static async Task TryExecuteAsync(string input, Action printLine, CancellationToken cancellationToken = default) { string trimmedInput = input.Trim(); @@ -43,8 +43,7 @@ public static class CommandManager commandHistory.Add(trimmedInput); } - foreach (KeyValuePair entry in commands - .OrderByDescending(entry => entry.Key.Length)) + foreach (KeyValuePair entry in commands.OrderByDescending(entry => entry.Key.Length)) { string commandName = entry.Key; @@ -61,6 +60,8 @@ public static class CommandManager arguments = trimmedInput[commandName.Length..].TrimStart(); } + cancellationToken.Register(async () => await entry.Value.StopAsync()); + await entry.Value.ExecuteAsync(arguments, printLine); return true; } diff --git a/UI/CLI/Commands/StartGuiCommand.cs b/UI/CLI/Commands/StartGuiCommand.cs index e3f145a..937d23a 100644 --- a/UI/CLI/Commands/StartGuiCommand.cs +++ b/UI/CLI/Commands/StartGuiCommand.cs @@ -18,11 +18,6 @@ public class StartGuiCommand : ICommand return Task.CompletedTask; } - foreach (Process process in ProcessManager.GetProcessesOfType()) - { - ProcessManager.StopProcess(process.Id); - } - _ = ProcessManager.SpawnProcess(); return Task.CompletedTask; } diff --git a/UI/CLI/Commands/StopGuiCommand.cs b/UI/CLI/Commands/StopGuiCommand.cs index f6d18da..9254c48 100644 --- a/UI/CLI/Commands/StopGuiCommand.cs +++ b/UI/CLI/Commands/StopGuiCommand.cs @@ -22,7 +22,5 @@ public class StopGuiCommand : ICommand { await ProcessManager.StopProcessAndWaitAsync(process.Id); } - - _ = ProcessManager.SpawnProcess(); } } diff --git a/UI/CLI/Commands/YesNtCommand.cs b/UI/CLI/Commands/YesNtCommand.cs index bb2551e..5fbd13e 100644 --- a/UI/CLI/Commands/YesNtCommand.cs +++ b/UI/CLI/Commands/YesNtCommand.cs @@ -12,10 +12,18 @@ namespace RemSox.UI.CLI.Commands public string Description => "Start the YesNt interpreter"; + private int processId; + public async Task ExecuteAsync(string? arguments, Action printLine) { - int processId = ProcessManager.SpawnProcess(arguments?.Split(',') ?? []); + processId = ProcessManager.SpawnProcess(arguments?.Split(',') ?? []); await ProcessManager.WaitForProcessExitAsync(processId); } + + public Task StopAsync() + { + ProcessManager.StopProcess(processId); + return Task.CompletedTask; + } } } \ No newline at end of file diff --git a/UI/CLI/ICommand.cs b/UI/CLI/ICommand.cs index 96a55ee..d68dea6 100644 --- a/UI/CLI/ICommand.cs +++ b/UI/CLI/ICommand.cs @@ -20,4 +20,9 @@ public interface ICommand /// The arguments provided to the command. /// A delegate to stream output lines to the current console or terminal. Task ExecuteAsync(string? arguments, Action printLine); + + /// + /// Interrupts the command if it's currently running. This is called when the user presses Ctrl+C in the CLI. + /// + Task StopAsync() => Task.CompletedTask; }