miniscript icon indicating copy to clipboard operation
miniscript copied to clipboard

[Feature request][cmd] Let Ctrl+C interrupt the running code, instead of aborting MiniScript

Open Withered-Flower-0422 opened this issue 2 years ago • 2 comments

When pressing Ctrl+C, you quit from MiniScript environment. It seems there's no way to interrupt the running code simply. Ctrl+C is more suitable to do a BREAK thing, not an ABORT thing. So just let Ctrl+C interrupt the running code, instead of aborting MiniScript. If you want to abort MiniScript, type Ctrl+Z. (This is already available.)

This is how python does. I feel it more reasonable. Python won't abort until you type Ctrl+Z.

Python 3.11.0 (main, Oct 24 2022, 18:26:48) [MSC v.1933 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> while 1:
...     pass
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyboardInterrupt // after pressing Ctrl+C, the code is interrupted, but not aborted.
>>>

See on Discord

Withered-Flower-0422 avatar Jan 29 '24 20:01 Withered-Flower-0422

Properly breaking out of the code (without exiting the environment) is more involved than it sounds, but it's certainly doable. For reference, here is the C# code that handles a break in Mini Micro:

	public bool Break(bool silent=false) {
		//Debug.Log($"Break({silent})");
		if (!silent) {
			var opts = env.GetMap("bootOpts");
			allowControlCBreak = opts.GetBool("controlC", true);
			if (!allowControlCBreak) return false;
		}
		
		// grab the full stack and tuck it away for future reference
		ValList stack = stackAtLastErr;
		if (stack == null) stack = Intrinsics.StackList(interpreter.vm);
		//Debug.Log($"Break found stack: {stack.ToString()}");
		
		// also find the first non-null entry, to display right away
		SourceLoc loc = null;
		if (interpreter.vm != null) {
			foreach (var stackLoc in interpreter.vm.GetStack()) {
				loc = stackLoc;
				if (loc != null) break;
			}
		}
		interpreter.Stop();
		console.AbortInput();
		console.keyBuffer.Clear();
		if (!silent) {
			string msg = "BREAK";
			if (loc != null) {
				msg += " at ";
				if (loc.context != null) msg += loc.context + " ";
				msg += "line " + loc.lineNum;
			}
			textDisplay.Print(msg + "\n");
			//Debug.Log("printed: " + msg);
		}
		// Reset the interpreter (creating a new VM), but copy the globals
		// and various type maps out of the old one.
		var oldVM = interpreter.vm;
		interpreter.Reset();
		interpreter.REPL("");	// (forces creation of a VM)
		CreateVersionMap();
		interpreter.vm.globalContext.variables = oldVM.globalContext.variables;
		interpreter.vm.listType = oldVM.listType;
		interpreter.vm.mapType = oldVM.mapType;
		interpreter.vm.numberType = oldVM.numberType;
		interpreter.vm.stringType = oldVM.stringType;
		interpreter.vm.versionMap = oldVM.versionMap;
		oldVM = null;

		// and set the _stackAtBreak global to our stack
		interpreter.vm.globalContext.variables.SetElem(_stackAtBreak, stack);
		//Debug.Log("Rebuilt VM and restored " + globals.Count + " globals");
		doLaunchShell = false;
		isRunningShell = false;
		runProgram = false;
		return true;
	}

JoeStrout avatar Jan 30 '24 03:01 JoeStrout

For C++, specifically for Windows, the handler would be set like this:

SetConsoleCtrlHandler(CtrlHandler, TRUE);

A sample handler:

#include <windows.h>

BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
{
    switch (fdwCtrlType)
    {
    case CTRL_C_EVENT:
        // MiniScript break here
        return TRUE; // We are handling this event.
    default:
        return FALSE; // We want other handlers to consume the event.
}

For *nix, the C++ implementation would need to deal with signals.

For the handler in C#, I haven't done this yet myself, but quick web-searching seems to indicate you set it like this:

Console.CancelKeyPress += new ConsoleCancelEventHandler(consoleBreakHandler)

A sample handler:

protected static void consoleBreakHandler(object sender, ConsoleCancelEventArgs args)
{
    // MiniScript break here
    args.Cancel = true; // We don't want the program to quit.
}

References:

  • https://learn.microsoft.com/en-us/windows/console/registering-a-control-handler-function
  • https://learn.microsoft.com/en-us/dotnet/api/system.console.cancelkeypress?view=net-8.0

BibleClinger avatar Jan 30 '24 04:01 BibleClinger