diff --git a/core/string/print_string.cpp b/core/string/print_string.cpp index 0f019c405f0..adceb6365e6 100644 --- a/core/string/print_string.cpp +++ b/core/string/print_string.cpp @@ -93,80 +93,178 @@ void __print_line_rich(const String &p_string) { // Convert a subset of BBCode tags to ANSI escape codes for correct display in the terminal. // Support of those ANSI escape codes varies across terminal emulators, // especially for italic and strikethrough. - String p_string_ansi = p_string; - p_string_ansi = p_string_ansi.replace("[b]", "\u001b[1m"); - p_string_ansi = p_string_ansi.replace("[/b]", "\u001b[22m"); - p_string_ansi = p_string_ansi.replace("[i]", "\u001b[3m"); - p_string_ansi = p_string_ansi.replace("[/i]", "\u001b[23m"); - p_string_ansi = p_string_ansi.replace("[u]", "\u001b[4m"); - p_string_ansi = p_string_ansi.replace("[/u]", "\u001b[24m"); - p_string_ansi = p_string_ansi.replace("[s]", "\u001b[9m"); - p_string_ansi = p_string_ansi.replace("[/s]", "\u001b[29m"); + String output; + int pos = 0; + while (pos <= p_string.length()) { + int brk_pos = p_string.find_char('[', pos); - p_string_ansi = p_string_ansi.replace("[indent]", " "); - p_string_ansi = p_string_ansi.replace("[/indent]", ""); - p_string_ansi = p_string_ansi.replace("[code]", "\u001b[2m"); - p_string_ansi = p_string_ansi.replace("[/code]", "\u001b[22m"); - p_string_ansi = p_string_ansi.replace("[url]", ""); - p_string_ansi = p_string_ansi.replace("[/url]", ""); - p_string_ansi = p_string_ansi.replace("[center]", "\n\t\t\t"); - p_string_ansi = p_string_ansi.replace("[/center]", ""); - p_string_ansi = p_string_ansi.replace("[right]", "\n\t\t\t\t\t\t"); - p_string_ansi = p_string_ansi.replace("[/right]", ""); + if (brk_pos < 0) { + brk_pos = p_string.length(); + } - if (p_string_ansi.contains("[color")) { - p_string_ansi = p_string_ansi.replace("[color=black]", "\u001b[30m"); - p_string_ansi = p_string_ansi.replace("[color=red]", "\u001b[91m"); - p_string_ansi = p_string_ansi.replace("[color=green]", "\u001b[92m"); - p_string_ansi = p_string_ansi.replace("[color=lime]", "\u001b[92m"); - p_string_ansi = p_string_ansi.replace("[color=yellow]", "\u001b[93m"); - p_string_ansi = p_string_ansi.replace("[color=blue]", "\u001b[94m"); - p_string_ansi = p_string_ansi.replace("[color=magenta]", "\u001b[95m"); - p_string_ansi = p_string_ansi.replace("[color=pink]", "\u001b[38;5;218m"); - p_string_ansi = p_string_ansi.replace("[color=purple]", "\u001b[38;5;98m"); - p_string_ansi = p_string_ansi.replace("[color=cyan]", "\u001b[96m"); - p_string_ansi = p_string_ansi.replace("[color=white]", "\u001b[97m"); - p_string_ansi = p_string_ansi.replace("[color=orange]", "\u001b[38;5;208m"); - p_string_ansi = p_string_ansi.replace("[color=gray]", "\u001b[90m"); - p_string_ansi = p_string_ansi.replace("[/color]", "\u001b[39m"); - } - if (p_string_ansi.contains("[bgcolor")) { - p_string_ansi = p_string_ansi.replace("[bgcolor=black]", "\u001b[40m"); - p_string_ansi = p_string_ansi.replace("[bgcolor=red]", "\u001b[101m"); - p_string_ansi = p_string_ansi.replace("[bgcolor=green]", "\u001b[102m"); - p_string_ansi = p_string_ansi.replace("[bgcolor=lime]", "\u001b[102m"); - p_string_ansi = p_string_ansi.replace("[bgcolor=yellow]", "\u001b[103m"); - p_string_ansi = p_string_ansi.replace("[bgcolor=blue]", "\u001b[104m"); - p_string_ansi = p_string_ansi.replace("[bgcolor=magenta]", "\u001b[105m"); - p_string_ansi = p_string_ansi.replace("[bgcolor=pink]", "\u001b[48;5;218m"); - p_string_ansi = p_string_ansi.replace("[bgcolor=purple]", "\u001b[48;5;98m"); - p_string_ansi = p_string_ansi.replace("[bgcolor=cyan]", "\u001b[106m"); - p_string_ansi = p_string_ansi.replace("[bgcolor=white]", "\u001b[107m"); - p_string_ansi = p_string_ansi.replace("[bgcolor=orange]", "\u001b[48;5;208m"); - p_string_ansi = p_string_ansi.replace("[bgcolor=gray]", "\u001b[100m"); - p_string_ansi = p_string_ansi.replace("[/bgcolor]", "\u001b[49m"); - } - if (p_string_ansi.contains("[fgcolor")) { - p_string_ansi = p_string_ansi.replace("[fgcolor=black]", "\u001b[30;40m"); - p_string_ansi = p_string_ansi.replace("[fgcolor=red]", "\u001b[91;101m"); - p_string_ansi = p_string_ansi.replace("[fgcolor=green]", "\u001b[92;102m"); - p_string_ansi = p_string_ansi.replace("[fgcolor=lime]", "\u001b[92;102m"); - p_string_ansi = p_string_ansi.replace("[fgcolor=yellow]", "\u001b[93;103m"); - p_string_ansi = p_string_ansi.replace("[fgcolor=blue]", "\u001b[94;104m"); - p_string_ansi = p_string_ansi.replace("[fgcolor=magenta]", "\u001b[95;105m"); - p_string_ansi = p_string_ansi.replace("[fgcolor=pink]", "\u001b[38;5;218;48;5;218m"); - p_string_ansi = p_string_ansi.replace("[fgcolor=purple]", "\u001b[38;5;98;48;5;98m"); - p_string_ansi = p_string_ansi.replace("[fgcolor=cyan]", "\u001b[96;106m"); - p_string_ansi = p_string_ansi.replace("[fgcolor=white]", "\u001b[97;107m"); - p_string_ansi = p_string_ansi.replace("[fgcolor=orange]", "\u001b[38;5;208;48;5;208m"); - p_string_ansi = p_string_ansi.replace("[fgcolor=gray]", "\u001b[90;100m"); - p_string_ansi = p_string_ansi.replace("[/fgcolor]", "\u001b[39;49m"); + String txt = brk_pos > pos ? p_string.substr(pos, brk_pos - pos) : ""; + if (brk_pos == p_string.length()) { + output += txt; + break; + } + + int brk_end = p_string.find_char(']', brk_pos + 1); + + if (brk_end == -1) { + txt += p_string.substr(brk_pos, p_string.length() - brk_pos); + output += txt; + break; + } + pos = brk_end + 1; + output += txt; + + String tag = p_string.substr(brk_pos + 1, brk_end - brk_pos - 1); + if (tag == "b") { + output += "\u001b[1m"; + } else if (tag == "/b") { + output += "\u001b[22m"; + } else if (tag == "i") { + output += "\u001b[3m"; + } else if (tag == "/i") { + output += "\u001b[23m"; + } else if (tag == "u") { + output += "\u001b[4m"; + } else if (tag == "/u") { + output += "\u001b[24m"; + } else if (tag == "s") { + output += "\u001b[9m"; + } else if (tag == "/s") { + output += "\u001b[29m"; + } else if (tag == "indent") { + output += " "; + } else if (tag == "/indent") { + output += ""; + } else if (tag == "code") { + output += "\u001b[2m"; + } else if (tag == "/code") { + output += "\u001b[22m"; + } else if (tag == "url") { + output += ""; + } else if (tag == "/url") { + output += ""; + } else if (tag == "center") { + output += "\n\t\t\t"; + } else if (tag == "center") { + output += ""; + } else if (tag == "right") { + output += "\n\t\t\t\t\t\t"; + } else if (tag == "/right") { + output += ""; + } else if (tag.begins_with("color=")) { + String color_name = tag.trim_prefix("color="); + if (color_name == "black") { + output += "\u001b[30m"; + } else if (color_name == "red") { + output += "\u001b[91m"; + } else if (color_name == "green") { + output += "\u001b[92m"; + } else if (color_name == "lime") { + output += "\u001b[92m"; + } else if (color_name == "yellow") { + output += "\u001b[93m"; + } else if (color_name == "blue") { + output += "\u001b[94m"; + } else if (color_name == "magenta") { + output += "\u001b[95m"; + } else if (color_name == "pink") { + output += "\u001b[38;5;218m"; + } else if (color_name == "purple") { + output += "\u001b[38;5;98m"; + } else if (color_name == "cyan") { + output += "\u001b[96m"; + } else if (color_name == "white") { + output += "\u001b[97m"; + } else if (color_name == "orange") { + output += "\u001b[38;5;208m"; + } else if (color_name == "gray") { + output += "\u001b[90m"; + } else { + Color c = Color::from_string(color_name, Color()); + output += vformat("\u001b[38;2;%d;%d;%dm", c.r * 255, c.g * 255, c.b * 255); + } + } else if (tag == "/color") { + output += "\u001b[39m"; + } else if (tag.begins_with("bgcolor=")) { + String color_name = tag.trim_prefix("bgcolor="); + if (color_name == "black") { + output += "\u001b[40m"; + } else if (color_name == "red") { + output += "\u001b[101m"; + } else if (color_name == "green") { + output += "\u001b[102m"; + } else if (color_name == "lime") { + output += "\u001b[102m"; + } else if (color_name == "yellow") { + output += "\u001b[103m"; + } else if (color_name == "blue") { + output += "\u001b[104m"; + } else if (color_name == "magenta") { + output += "\u001b[105m"; + } else if (color_name == "pink") { + output += "\u001b[48;5;218m"; + } else if (color_name == "purple") { + output += "\u001b[48;5;98m"; + } else if (color_name == "cyan") { + output += "\u001b[106m"; + } else if (color_name == "white") { + output += "\u001b[107m"; + } else if (color_name == "orange") { + output += "\u001b[48;5;208m"; + } else if (color_name == "gray") { + output += "\u001b[100m"; + } else { + Color c = Color::from_string(color_name, Color()); + output += vformat("\u001b[48;2;%d;%d;%dm", c.r * 255, c.g * 255, c.b * 255); + } + } else if (tag == "/bgcolor") { + output += "\u001b[49m"; + } else if (tag.begins_with("fgcolor=")) { + String color_name = tag.trim_prefix("fgcolor="); + if (color_name == "black") { + output += "\u001b[30;40m"; + } else if (color_name == "red") { + output += "\u001b[91;101m"; + } else if (color_name == "green") { + output += "\u001b[92;102m"; + } else if (color_name == "lime") { + output += "\u001b[92;102m"; + } else if (color_name == "yellow") { + output += "\u001b[93;103m"; + } else if (color_name == "blue") { + output += "\u001b[94;104m"; + } else if (color_name == "magenta") { + output += "\u001b[95;105m"; + } else if (color_name == "pink") { + output += "\u001b[38;5;218;48;5;218m"; + } else if (color_name == "purple") { + output += "\u001b[38;5;98;48;5;98m"; + } else if (color_name == "cyan") { + output += "\u001b[96;106m"; + } else if (color_name == "white") { + output += "\u001b[97;107m"; + } else if (color_name == "orange") { + output += "\u001b[38;5;208;48;5;208m"; + } else if (color_name == "gray") { + output += "\u001b[90;100m"; + } else { + Color c = Color::from_string(color_name, Color()); + output += vformat("\u001b[38;2;%d;%d;%d;48;2;%d;%d;%dm", c.r * 255, c.g * 255, c.b * 255, c.r * 255, c.g * 255, c.b * 255); + } + } else if (tag == "/fgcolor") { + output += "\u001b[39;49m"; + } else { + output += vformat("[%s]", tag); + } } + output += "\u001b[0m"; // Reset. - p_string_ansi += "\u001b[0m"; // Reset. - - OS::get_singleton()->print_rich("%s\n", p_string_ansi.utf8().get_data()); + OS::get_singleton()->print_rich("%s\n", output.utf8().get_data()); _global_lock(); PrintHandlerList *l = print_handler_list; diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 55d00b6cf90..0d0e0947edd 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -863,7 +863,6 @@ Converts one or more arguments of any type to string in the best way possible and prints them to the console. The following BBCode tags are supported: [code]b[/code], [code]i[/code], [code]u[/code], [code]s[/code], [code]indent[/code], [code]code[/code], [code]url[/code], [code]center[/code], [code]right[/code], [code]color[/code], [code]bgcolor[/code], [code]fgcolor[/code]. - Color tags only support the following named colors: [code]black[/code], [code]red[/code], [code]green[/code], [code]yellow[/code], [code]blue[/code], [code]magenta[/code], [code]pink[/code], [code]purple[/code], [code]cyan[/code], [code]white[/code], [code]orange[/code], [code]gray[/code]. Hexadecimal color codes are not supported. URL tags only support URLs wrapped by a URL tag, not URLs with a different title. When printing to standard output, the supported subset of BBCode is converted to ANSI escape codes for the terminal emulator to display. Support for ANSI escape codes varies across terminal emulators, especially for italic and strikethrough. In standard output, [code]code[/code] is represented with faint text but without any font change. Unsupported tags are left as-is in standard output. [codeblocks]