Skip to main content

godot_core/global/
print.rs

1/*
2 * Copyright (c) godot-rust; Bromeon and contributors.
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
6 */
7
8//! Printing and logging functionality.
9
10// https://stackoverflow.com/a/40234666
11#[macro_export]
12#[doc(hidden)]
13macro_rules! inner_function {
14    () => {{
15        fn f() {}
16        fn type_name_of<T>(_: T) -> &'static str {
17            std::any::type_name::<T>()
18        }
19        let name = type_name_of(f);
20        name.strip_suffix("::f").unwrap()
21    }};
22}
23
24#[macro_export]
25#[doc(hidden)]
26macro_rules! inner_godot_msg {
27    // FIXME expr needs to be parenthesised, see usages
28    ($godot_fn:ident; $fmt:literal $(, $args:expr_2021)* $(,)?) => {
29    //($($args:tt),* $(,)?) => {
30        {
31            let msg = format!("{}\0", format_args!($fmt $(, $args)*));
32            // Godot supports Unicode messages, not only ASCII. See `do_panic` test.
33
34            // Check whether engine is loaded, otherwise fall back to stderr.
35            if $crate::sys::is_initialized() {
36                let function = format!("{}\0", $crate::inner_function!());
37                // SAFETY: interface_fn! returns valid function pointer; string pointers are valid for the call duration.
38                #[allow(unused_unsafe)] // False positive; omitting `unsafe` causes compile error.
39                unsafe {
40                    $crate::sys::interface_fn!($godot_fn)(
41                        $crate::sys::c_str_from_str(&msg),
42                        $crate::sys::c_str_from_str(&function),
43                        $crate::sys::c_str_from_str(concat!(file!(), "\0")),
44                        line!() as i32,
45                        $crate::sys::conv::SYS_FALSE, // Whether to create a toast notification in editor.
46                    )
47                };
48            } else {
49                eprintln!("[{}] {}", stringify!($godot_fn), &msg[..msg.len() - 1]);
50            }
51        }
52    };
53}
54
55/// Pushes a warning message to Godot's built-in debugger and to the OS terminal.
56///
57/// # See also
58/// [`godot_print!`](macro.godot_print.html) and [`godot_error!`](macro.godot_error.html).
59///
60/// Related to the utility function [`global::push_warning()`](crate::global::push_warning).
61///
62/// _Godot equivalent: [`@GlobalScope.push_warning()`](https://docs.godotengine.org/en/stable/classes/class_@globalscope.html#class-globalscope-method-push-warning)_.
63#[macro_export]
64macro_rules! godot_warn {
65    ($fmt:literal $(, $args:expr_2021)* $(,)?) => {
66        $crate::inner_godot_msg!(print_warning; $fmt $(, $args)*);
67    };
68}
69
70/// Pushes an error message to Godot's built-in debugger and to the OS terminal.
71///
72/// # See also
73/// [`godot_print!`](macro.godot_print.html) and [`godot_warn!`](macro.godot_warn.html).
74/// For script errors (less relevant in Rust), use [`godot_script_error!`](macro.godot_script_error.html).
75///
76/// Related to the utility function [`global::push_error()`][crate::global::push_error].
77///
78/// _Godot equivalent: [`@GlobalScope.push_error()`](https://docs.godotengine.org/en/stable/classes/class_@globalscope.html#class-globalscope-method-push-error)_.
79#[macro_export]
80macro_rules! godot_error {
81    ($fmt:literal $(, $args:expr_2021)* $(,)?) => {
82        $crate::inner_godot_msg!(print_error; $fmt $(, $args)*);
83    };
84}
85
86/// Logs a script error to Godot's built-in debugger and to the OS terminal.
87///
88/// This is rarely needed in Rust; script errors are typically emitted by the GDScript parser.
89///
90/// # See also
91/// [`godot_error!`](macro.godot_error.html) for a general error message.
92///
93///
94#[macro_export]
95macro_rules! godot_script_error {
96    ($fmt:literal $(, $args:expr_2021)* $(,)?) => {
97        $crate::inner_godot_msg!(print_script_error; $fmt $(, $args)*);
98    };
99}
100
101/// Prints to the Godot console.
102///
103/// Automatically appends a newline character at the end of the message.
104///
105/// Used exactly like standard [`println!`]:
106/// ```no_run
107/// use godot::global::godot_print;
108///
109/// let version = 4;
110/// godot_print!("Hello, Godot {version}!");
111/// ```
112///
113/// # See also
114/// [`godot_print_rich!`](macro.godot_print_rich.html) for a slower alternative that supports BBCode, color and URL tags.
115/// To print Godot errors and warnings, use [`godot_error!`](macro.godot_error.html) and [`godot_warn!`](macro.godot_warn.html), respectively.
116///
117/// This uses the underlying [`global::print()`][crate::global::print] function, which takes a variable-length slice of variants.
118///
119/// _Godot equivalent: [`@GlobalScope.print()`](https://docs.godotengine.org/en/stable/classes/class_@globalscope.html#class-globalscope-method-print)_.
120#[macro_export]
121macro_rules! godot_print {
122    ($fmt:literal $(, $args:expr_2021)* $(,)?) => {
123        $crate::global::print(&[
124            $crate::builtin::Variant::from(
125                format!($fmt $(, $args)*)
126            )
127        ])
128    };
129}
130
131/// Prints to the Godot console. Supports BBCode, color and URL tags.
132///
133/// Slower than [`godot_print!`](macro.godot_print_rich.html).
134///
135/// _Godot equivalent: [`@GlobalScope.print_rich()`](https://docs.godotengine.org/en/stable/classes/class_@globalscope.html#class-globalscope-method-print-rich)_.
136#[macro_export]
137macro_rules! godot_print_rich {
138    ($fmt:literal $(, $args:expr_2021)* $(,)?) => {
139        $crate::global::print_rich(&[
140            $crate::builtin::Variant::from(
141                format!($fmt $(, $args)*)
142            )
143        ])
144    };
145}
146
147/// Concatenates format-style arguments into a `GString`.
148///
149/// Works similar to Rust's standard [`format!`] macro but returns a Godot `GString`.
150///
151/// # Example
152/// ```no_run
153/// use godot::builtin::GString;
154/// use godot::global::godot_str;
155///
156/// let name = "Player";
157/// let score = 100;
158/// let message: GString = godot_str!("The {name} scored {score} points!");
159/// ```
160///
161/// # See also
162/// This macro uses the underlying [`global::str()`][crate::global::str] function, which takes a variable-length slice of variants.
163///
164/// _Godot equivalent: [`@GlobalScope.str()`](https://docs.godotengine.org/en/stable/classes/class_@globalscope.html#class-globalscope-method-str)_.
165#[macro_export]
166macro_rules! godot_str {
167    ($fmt:literal $(, $args:expr_2021)* $(,)?) => {
168        $crate::global::str(&[
169            $crate::builtin::Variant::from(
170                format!($fmt $(, $args)*)
171            )
172        ])
173    };
174}