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 	version(D_Exceptions) throw new AssertError(msg, file, line);
29 	else
30 	{
31 		assertHandler = null;
32 		assert(0, msg);
33 	}
34 }
35 
36 /++
37 The debug-mode Godot-D assert handler redirects assert messages to the Godot
38 error handlers (including Debugger tab in editor and system console).
39 
40 Unlike the default D assert handler, this one doesn't terminate the program,
41 allowing the messages to remain in Godot's Debugger tab and matching how Godot
42 error macros behave.
43 +/
44 nothrow
45 void godotAssertHandlerEditorDebug(string file, size_t line, string msg)
46 {
47 	import core.exception;
48 	import std.experimental.allocator.mallocator;
49 	
50 	char[] buffer = cast(char[])Mallocator.instance.allocate(file.length + msg.length + 2);
51 	scope(exit) Mallocator.instance.deallocate(cast(void[])buffer);
52 	
53 	buffer[0..file.length] = file[];
54 	buffer[file.length] = '\0';
55 	buffer[file.length+1 .. $-1] = msg[];
56 	buffer[$-1] = '\0';
57 	
58 	_godot_api.godot_print_error(&buffer.ptr[file.length+1], "", buffer.ptr, cast(int)line);
59 	
60 	//version(assert) // any `assert(x)` gets compiled; usually a debug version
61 	//{
62 	//	// TODO: if in Editor Debugger, debug_break like GDScript asserts
63 	//}
64 	//else // only `assert(0)`/`assert(false)` get compiled; usually a release version
65 	{
66 		// crash on always-false asserts
67 		version(D_Exceptions) throw new AssertError(msg, file, line);
68 		else
69 		{
70 			assertHandler = null;
71 			assert(0, msg);
72 		}
73 	}
74 }
75 
76 /**
77 Print to Godot's console and stdout.
78 
79 Params:
80 	args = any Godot-compatible types or strings
81 */
82 void print(Args...)(Args args)
83 {
84 	import godot.core.string, godot.core.variant;
85 	
86 	String str;
87 	static if(Args.length == 0) str = String(" ");
88 	foreach(arg; args)
89 	{
90 		static if(is(typeof(arg) : String)) str ~= arg;
91 		else static if(is(typeof(arg) : string)) str ~= String(arg);
92 		else static if(is(typeof(arg) : Variant)) str ~= arg.as!String;
93 		else static if(Variant.compatibleToGodot!(typeof(arg))) str ~= Variant(arg).as!String;
94 		else static assert(0, "Unable to print type "~typeof(arg).stringof);
95 	}
96 	_godot_api.godot_print(&str._godot_string);
97 }
98