1 /++
2 Integration with Godot editor's output and debugger tabs
3 +/
4 module godot.d.output;
5 
6 import godot.c, godot.core;
7 
8 /++
9 The release-mode Godot-D assert handler redirects assert messages to the Godot
10 error handlers and terminates the program.
11 +/
12 nothrow
13 void godotAssertHandlerCrash(string file, size_t line, string msg)
14 {
15 	import core.exception;
16 	import std.experimental.allocator.mallocator;
17 	
18 	char[] buffer = cast(char[])Mallocator.instance.allocate(file.length + msg.length + 2);
19 	scope(exit) Mallocator.instance.deallocate(cast(void[])buffer);
20 	
21 	buffer[0..file.length] = file[];
22 	buffer[file.length] = '\0';
23 	buffer[file.length+1 .. $-1] = msg[];
24 	buffer[$-1] = '\0';
25 	
26 	_godot_api.godot_print_error(&buffer.ptr[file.length+1], "", buffer.ptr, cast(int)line);
27 	
28 	throw new AssertError(msg, file, line);
29 }
30 
31 /++
32 The debug-mode Godot-D assert handler redirects assert messages to the Godot
33 error handlers (including Debugger tab in editor and system console).
34 
35 Unlike the default D assert handler, this one doesn't terminate the program,
36 allowing the messages to remain in Godot's Debugger tab and matching how Godot
37 error macros behave.
38 +/
39 nothrow
40 void godotAssertHandlerEditorDebug(string file, size_t line, string msg)
41 {
42 	import core.exception;
43 	import std.experimental.allocator.mallocator;
44 	
45 	char[] buffer = cast(char[])Mallocator.instance.allocate(file.length + msg.length + 2);
46 	scope(exit) Mallocator.instance.deallocate(cast(void[])buffer);
47 	
48 	buffer[0..file.length] = file[];
49 	buffer[file.length] = '\0';
50 	buffer[file.length+1 .. $-1] = msg[];
51 	buffer[$-1] = '\0';
52 	
53 	_godot_api.godot_print_error(&buffer.ptr[file.length+1], "", buffer.ptr, cast(int)line);
54 	
55 	version(assert) // any `assert(x)` gets compiled; usually a debug version
56 	{
57 		// TODO: if in Editor Debugger, debug_break like GDScript asserts
58 	}
59 	else // only `assert(0)`/`assert(false)` get compiled; usually a release version
60 	{
61 		// crash on always-false asserts
62 		throw new AssertError(msg, file, line);
63 	}
64 }
65 
66 /**
67 Print to Godot's console and stdout.
68 
69 Params:
70 	args = any Godot-compatible types or strings
71 */
72 void print(Args...)(Args args)
73 {
74 	import godot.core.string, godot.core.variant;
75 	
76 	String str;
77 	static if(Args.length == 0) str = String(" ");
78 	foreach(arg; args)
79 	{
80 		static if(is(typeof(arg) : String)) str ~= arg;
81 		else static if(is(typeof(arg) : string)) str ~= String(arg);
82 		else static if(Variant.compatibleToGodot!(typeof(arg))) str ~= Variant(arg).as!String;
83 		else static assert(0, "Unable to print type "~typeof(arg).stringof);
84 	}
85 	_godot_api.godot_print(&str._godot_string);
86 }
87