feat(miscellaneous): add console operation functions
This commit is contained in:
		
							
								
								
									
										462
									
								
								Redcraft.Utility/Source/Private/Miscellaneous/Console.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										462
									
								
								Redcraft.Utility/Source/Private/Miscellaneous/Console.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,462 @@ | |||||||
|  | #include "Miscellaneous/Console.h" | ||||||
|  |  | ||||||
|  | #include <cstdio> | ||||||
|  |  | ||||||
|  | #if PLATFORM_WINDOWS | ||||||
|  | #	undef TEXT | ||||||
|  | #	include <windows.h> | ||||||
|  | #elif PLATFORM_LINUX | ||||||
|  | #	include <sys/ioctl.h> | ||||||
|  | #	include <unistd.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | NAMESPACE_REDCRAFT_BEGIN | ||||||
|  | NAMESPACE_MODULE_BEGIN(Redcraft) | ||||||
|  | NAMESPACE_MODULE_BEGIN(Utility) | ||||||
|  |  | ||||||
|  | #if PLATFORM_WINDOWS | ||||||
|  |  | ||||||
|  | NODISCARD bool InitANSIConsole() | ||||||
|  | { | ||||||
|  | 	static bool bResult = [] | ||||||
|  | 	{ | ||||||
|  | 		HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); | ||||||
|  |  | ||||||
|  | 		if (Console == INVALID_HANDLE_VALUE) return false; | ||||||
|  |  | ||||||
|  | 		DWORD ConsoleMode = 0; | ||||||
|  |  | ||||||
|  | 		if (!GetConsoleMode(Console, &ConsoleMode)) return false; | ||||||
|  |  | ||||||
|  | 		ConsoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; | ||||||
|  |  | ||||||
|  | 		if (!SetConsoleMode(Console, ConsoleMode)) return false; | ||||||
|  |  | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | 	(); | ||||||
|  |  | ||||||
|  | 	return bResult; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | EColor GForegroundColor = EColor::Default; | ||||||
|  | EColor GBackgroundColor = EColor::Default; | ||||||
|  |  | ||||||
|  | EColor GetForegroundColor() | ||||||
|  | { | ||||||
|  | #	if PLATFORM_WINDOWS | ||||||
|  | 	{ | ||||||
|  | 		if (InitANSIConsole()) return GForegroundColor; | ||||||
|  |  | ||||||
|  | 		const HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); | ||||||
|  |  | ||||||
|  | 		if (Console == INVALID_HANDLE_VALUE) return EColor::Default; | ||||||
|  |  | ||||||
|  | 		CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; | ||||||
|  |  | ||||||
|  | 		if (!GetConsoleScreenBufferInfo(Console, &ConsoleInfo)) return EColor::Default; | ||||||
|  |  | ||||||
|  | 		const WORD Color = ConsoleInfo.wAttributes; | ||||||
|  |  | ||||||
|  | 		EColor Result = EColor::Black; | ||||||
|  |  | ||||||
|  | 		if (Color & FOREGROUND_RED)       Result |= EColor::Red; | ||||||
|  | 		if (Color & FOREGROUND_GREEN)     Result |= EColor::Green; | ||||||
|  | 		if (Color & FOREGROUND_BLUE)      Result |= EColor::Blue; | ||||||
|  | 		if (Color & FOREGROUND_INTENSITY) Result |= EColor::Intensity; | ||||||
|  |  | ||||||
|  | 		return Result; | ||||||
|  | 	} | ||||||
|  | #	endif | ||||||
|  |  | ||||||
|  | 	return GForegroundColor; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | EColor GetBackgroundColor() | ||||||
|  | { | ||||||
|  | #	if PLATFORM_WINDOWS | ||||||
|  | 	{ | ||||||
|  | 		if (InitANSIConsole()) return GBackgroundColor; | ||||||
|  |  | ||||||
|  | 		const HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); | ||||||
|  |  | ||||||
|  | 		if (Console == INVALID_HANDLE_VALUE) return EColor::Default; | ||||||
|  |  | ||||||
|  | 		CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; | ||||||
|  |  | ||||||
|  | 		if (!GetConsoleScreenBufferInfo(Console, &ConsoleInfo)) return EColor::Default; | ||||||
|  |  | ||||||
|  | 		const WORD Color = ConsoleInfo.wAttributes; | ||||||
|  |  | ||||||
|  | 		EColor Result = EColor::Black; | ||||||
|  |  | ||||||
|  | 		if (Color & BACKGROUND_RED)       Result |= EColor::Red; | ||||||
|  | 		if (Color & BACKGROUND_GREEN)     Result |= EColor::Green; | ||||||
|  | 		if (Color & BACKGROUND_BLUE)      Result |= EColor::Blue; | ||||||
|  | 		if (Color & BACKGROUND_INTENSITY) Result |= EColor::Intensity; | ||||||
|  |  | ||||||
|  | 		return Result; | ||||||
|  | 	} | ||||||
|  | #	endif | ||||||
|  |  | ||||||
|  | 	return GBackgroundColor; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | EColor SetForegroundColor(EColor InColor) | ||||||
|  | { | ||||||
|  | 	if (IsOutputRedirected()) return GetForegroundColor(); | ||||||
|  |  | ||||||
|  | #	if PLATFORM_WINDOWS | ||||||
|  | 	{ | ||||||
|  | 		if (!InitANSIConsole()) | ||||||
|  | 		{ | ||||||
|  | 			const HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); | ||||||
|  |  | ||||||
|  | 			if (Console == INVALID_HANDLE_VALUE) return GetForegroundColor(); | ||||||
|  |  | ||||||
|  | 			CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; | ||||||
|  |  | ||||||
|  | 			if (!GetConsoleScreenBufferInfo(Console, &ConsoleInfo)) return GetForegroundColor(); | ||||||
|  |  | ||||||
|  | 			WORD Color = ConsoleInfo.wAttributes & ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); | ||||||
|  |  | ||||||
|  | 			if (InColor == EColor::Default) InColor = EColor::White; | ||||||
|  |  | ||||||
|  | 			if (!!(InColor & EColor::Red))       Color |= FOREGROUND_RED; | ||||||
|  | 			if (!!(InColor & EColor::Green))     Color |= FOREGROUND_GREEN; | ||||||
|  | 			if (!!(InColor & EColor::Blue))      Color |= FOREGROUND_BLUE; | ||||||
|  | 			if (!!(InColor & EColor::Intensity)) Color |= FOREGROUND_INTENSITY; | ||||||
|  |  | ||||||
|  | 			if (!SetConsoleTextAttribute(Console, Color)) return GetForegroundColor(); | ||||||
|  |  | ||||||
|  | 			return InColor; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | #	endif | ||||||
|  |  | ||||||
|  | #	if PLATFORM_WINDOWS || PLATFORM_LINUX | ||||||
|  | 	{ | ||||||
|  | 		int Result; | ||||||
|  |  | ||||||
|  | 		switch (InColor) | ||||||
|  | 		{ | ||||||
|  | 		case EColor::Black:         Result = std::fputs("\033[30m", stdout); break; | ||||||
|  | 		case EColor::Red:           Result = std::fputs("\033[31m", stdout); break; | ||||||
|  | 		case EColor::Green:         Result = std::fputs("\033[32m", stdout); break; | ||||||
|  | 		case EColor::Yellow:        Result = std::fputs("\033[33m", stdout); break; | ||||||
|  | 		case EColor::Blue:          Result = std::fputs("\033[34m", stdout); break; | ||||||
|  | 		case EColor::Magenta:       Result = std::fputs("\033[35m", stdout); break; | ||||||
|  | 		case EColor::Cyan:          Result = std::fputs("\033[36m", stdout); break; | ||||||
|  | 		case EColor::White:         Result = std::fputs("\033[37m", stdout); break; | ||||||
|  | 		case EColor::BrightBlack:   Result = std::fputs("\033[90m", stdout); break; | ||||||
|  | 		case EColor::BrightRed:     Result = std::fputs("\033[91m", stdout); break; | ||||||
|  | 		case EColor::BrightGreen:   Result = std::fputs("\033[92m", stdout); break; | ||||||
|  | 		case EColor::BrightYellow:  Result = std::fputs("\033[93m", stdout); break; | ||||||
|  | 		case EColor::BrightBlue:    Result = std::fputs("\033[94m", stdout); break; | ||||||
|  | 		case EColor::BrightMagenta: Result = std::fputs("\033[95m", stdout); break; | ||||||
|  | 		case EColor::BrightCyan:    Result = std::fputs("\033[96m", stdout); break; | ||||||
|  | 		case EColor::BrightWhite:   Result = std::fputs("\033[97m", stdout); break; | ||||||
|  | 		default:                    Result = std::fputs("\033[39m", stdout); break; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (Result == EOF) return GetForegroundColor(); | ||||||
|  |  | ||||||
|  | 		return GForegroundColor = InColor; | ||||||
|  | 	} | ||||||
|  | #	endif | ||||||
|  |  | ||||||
|  | 	return GetForegroundColor(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | EColor SetBackgroundColor(EColor InColor) | ||||||
|  | { | ||||||
|  | 	if (IsOutputRedirected()) return GetBackgroundColor(); | ||||||
|  |  | ||||||
|  | #	if PLATFORM_WINDOWS | ||||||
|  | 	{ | ||||||
|  | 		if (!InitANSIConsole()) | ||||||
|  | 		{ | ||||||
|  | 			const HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); | ||||||
|  |  | ||||||
|  | 			if (Console == INVALID_HANDLE_VALUE) return GetBackgroundColor(); | ||||||
|  |  | ||||||
|  | 			CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; | ||||||
|  |  | ||||||
|  | 			if (!GetConsoleScreenBufferInfo(Console, &ConsoleInfo)) return GetBackgroundColor(); | ||||||
|  |  | ||||||
|  | 			WORD Color = ConsoleInfo.wAttributes & ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY); | ||||||
|  |  | ||||||
|  | 			if (InColor == EColor::Default) InColor = EColor::Black; | ||||||
|  |  | ||||||
|  | 			if (!!(InColor & EColor::Red))       Color |= BACKGROUND_RED; | ||||||
|  | 			if (!!(InColor & EColor::Green))     Color |= BACKGROUND_GREEN; | ||||||
|  | 			if (!!(InColor & EColor::Blue))      Color |= BACKGROUND_BLUE; | ||||||
|  | 			if (!!(InColor & EColor::Intensity)) Color |= BACKGROUND_INTENSITY; | ||||||
|  |  | ||||||
|  | 			if (!SetConsoleTextAttribute(Console, Color)) return GetBackgroundColor(); | ||||||
|  |  | ||||||
|  | 			return InColor; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | #	endif | ||||||
|  |  | ||||||
|  | #	if PLATFORM_WINDOWS || PLATFORM_LINUX | ||||||
|  | 	{ | ||||||
|  | 		int Result; | ||||||
|  |  | ||||||
|  | 		switch (InColor) | ||||||
|  | 		{ | ||||||
|  | 		case EColor::Black:         Result = std::fputs("\033[40m",  stdout); break; | ||||||
|  | 		case EColor::Red:           Result = std::fputs("\033[41m",  stdout); break; | ||||||
|  | 		case EColor::Green:         Result = std::fputs("\033[42m",  stdout); break; | ||||||
|  | 		case EColor::Yellow:        Result = std::fputs("\033[43m",  stdout); break; | ||||||
|  | 		case EColor::Blue:          Result = std::fputs("\033[44m",  stdout); break; | ||||||
|  | 		case EColor::Magenta:       Result = std::fputs("\033[45m",  stdout); break; | ||||||
|  | 		case EColor::Cyan:          Result = std::fputs("\033[46m",  stdout); break; | ||||||
|  | 		case EColor::White:         Result = std::fputs("\033[47m",  stdout); break; | ||||||
|  | 		case EColor::BrightBlack:   Result = std::fputs("\033[100m", stdout); break; | ||||||
|  | 		case EColor::BrightRed:     Result = std::fputs("\033[101m", stdout); break; | ||||||
|  | 		case EColor::BrightGreen:   Result = std::fputs("\033[102m", stdout); break; | ||||||
|  | 		case EColor::BrightYellow:  Result = std::fputs("\033[103m", stdout); break; | ||||||
|  | 		case EColor::BrightBlue:    Result = std::fputs("\033[104m", stdout); break; | ||||||
|  | 		case EColor::BrightMagenta: Result = std::fputs("\033[105m", stdout); break; | ||||||
|  | 		case EColor::BrightCyan:    Result = std::fputs("\033[106m", stdout); break; | ||||||
|  | 		case EColor::BrightWhite:   Result = std::fputs("\033[107m", stdout); break; | ||||||
|  | 		default:                    Result = std::fputs("\033[49m",  stdout); break; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (Result == EOF) return GetBackgroundColor(); | ||||||
|  |  | ||||||
|  | 		return GBackgroundColor = InColor; | ||||||
|  | 	} | ||||||
|  | #	endif | ||||||
|  |  | ||||||
|  | 	return GetBackgroundColor(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint GetWindowWidth() | ||||||
|  | { | ||||||
|  | #	if PLATFORM_WINDOWS | ||||||
|  | 	{ | ||||||
|  | 		const HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); | ||||||
|  |  | ||||||
|  | 		if (Console == INVALID_HANDLE_VALUE) return static_cast<uint>(-1); | ||||||
|  |  | ||||||
|  | 		CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; | ||||||
|  |  | ||||||
|  | 		if (!GetConsoleScreenBufferInfo(Console, &ConsoleInfo)) return static_cast<uint>(-1); | ||||||
|  |  | ||||||
|  | 		return static_cast<uint>(ConsoleInfo.srWindow.Right - ConsoleInfo.srWindow.Left + 1); | ||||||
|  | 	} | ||||||
|  | #	elif PLATFORM_LINUX | ||||||
|  | 	{ | ||||||
|  | 		winsize Size; | ||||||
|  |  | ||||||
|  | 		if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &Size) == -1) return static_cast<uint>(-1); | ||||||
|  |  | ||||||
|  | 		return static_cast<uint>(Size.ws_col); | ||||||
|  | 	} | ||||||
|  | #	endif | ||||||
|  |  | ||||||
|  | 	return static_cast<uint>(-1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint GetWindowHeight() | ||||||
|  | { | ||||||
|  | #	if PLATFORM_WINDOWS | ||||||
|  | 	{ | ||||||
|  | 		const HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); | ||||||
|  |  | ||||||
|  | 		if (Console == INVALID_HANDLE_VALUE) return static_cast<uint>(-1); | ||||||
|  |  | ||||||
|  | 		CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; | ||||||
|  |  | ||||||
|  | 		if (!GetConsoleScreenBufferInfo(Console, &ConsoleInfo)) return static_cast<uint>(-1); | ||||||
|  |  | ||||||
|  | 		return static_cast<uint>(ConsoleInfo.srWindow.Bottom - ConsoleInfo.srWindow.Top + 1); | ||||||
|  | 	} | ||||||
|  | #	elif PLATFORM_LINUX | ||||||
|  | 	{ | ||||||
|  | 		winsize Size; | ||||||
|  |  | ||||||
|  | 		if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &Size) == -1) return static_cast<uint>(-1); | ||||||
|  |  | ||||||
|  | 		return static_cast<uint>(Size.ws_row); | ||||||
|  | 	} | ||||||
|  | #	endif | ||||||
|  |  | ||||||
|  | 	return static_cast<uint>(-1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool IsInputRedirected() | ||||||
|  | { | ||||||
|  | #	if PLATFORM_WINDOWS | ||||||
|  | 	{ | ||||||
|  | 		const HANDLE StandardInput = GetStdHandle(STD_INPUT_HANDLE); | ||||||
|  |  | ||||||
|  | 		if (StandardInput == INVALID_HANDLE_VALUE) return false; | ||||||
|  |  | ||||||
|  | 		DWORD FileType = GetFileType(StandardInput); | ||||||
|  |  | ||||||
|  | 		return FileType != FILE_TYPE_CHAR; | ||||||
|  | 	} | ||||||
|  | #	elif PLATFORM_LINUX | ||||||
|  | 	{ | ||||||
|  | 		return isatty(fileno(stdin)) == 0; | ||||||
|  | 	} | ||||||
|  | #	endif | ||||||
|  |  | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool IsOutputRedirected() | ||||||
|  | { | ||||||
|  | #	if PLATFORM_WINDOWS | ||||||
|  | 	{ | ||||||
|  | 		const HANDLE StandardOutput = GetStdHandle(STD_OUTPUT_HANDLE); | ||||||
|  |  | ||||||
|  | 		if (StandardOutput == INVALID_HANDLE_VALUE) return false; | ||||||
|  |  | ||||||
|  | 		DWORD FileType = GetFileType(StandardOutput); | ||||||
|  |  | ||||||
|  | 		return FileType != FILE_TYPE_CHAR; | ||||||
|  | 	} | ||||||
|  | #	elif PLATFORM_LINUX | ||||||
|  | 	{ | ||||||
|  | 		return isatty(fileno(stdout)) == 0; | ||||||
|  | 	} | ||||||
|  | #	endif | ||||||
|  |  | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool IsErrorRedirected() | ||||||
|  | { | ||||||
|  | #	if PLATFORM_WINDOWS | ||||||
|  | 	{ | ||||||
|  | 		const HANDLE StandardError = GetStdHandle(STD_ERROR_HANDLE); | ||||||
|  |  | ||||||
|  | 		if (StandardError == INVALID_HANDLE_VALUE) return false; | ||||||
|  |  | ||||||
|  | 		DWORD FileType = GetFileType(StandardError); | ||||||
|  |  | ||||||
|  | 		return FileType != FILE_TYPE_CHAR; | ||||||
|  | 	} | ||||||
|  | #	elif PLATFORM_LINUX | ||||||
|  | 	{ | ||||||
|  | 		return isatty(fileno(stderr)) == 0; | ||||||
|  | 	} | ||||||
|  | #	endif | ||||||
|  |  | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Clear() | ||||||
|  | { | ||||||
|  | 	if (IsOutputRedirected()) return; | ||||||
|  |  | ||||||
|  | #	if PLATFORM_WINDOWS | ||||||
|  | 	{ | ||||||
|  | 		std::system("cls"); | ||||||
|  | 	} | ||||||
|  | #	elif PLATFORM_LINUX | ||||||
|  | 	{ | ||||||
|  | 		Ignore = std::fputs("\033[2J\033[1;1H", stdout); | ||||||
|  | 	} | ||||||
|  | #	endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | char Input(bool bEcho) | ||||||
|  | { | ||||||
|  | 	if (bEcho || IsOutputRedirected()) | ||||||
|  | 	{ | ||||||
|  | 		const int Result = std::getchar(); | ||||||
|  |  | ||||||
|  | 		if (Result == EOF) return static_cast<char>(-1); | ||||||
|  |  | ||||||
|  | 		return static_cast<char>(Result); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | #	if PLATFORM_WINDOWS | ||||||
|  | 	{ | ||||||
|  | 		const HANDLE Console = GetStdHandle(STD_INPUT_HANDLE); | ||||||
|  |  | ||||||
|  | 		if (Console == INVALID_HANDLE_VALUE) return static_cast<char>(-1); | ||||||
|  |  | ||||||
|  | 		DWORD ConsoleMode = 0; | ||||||
|  |  | ||||||
|  | 		GetConsoleMode(Console, &ConsoleMode); | ||||||
|  |  | ||||||
|  | 		SetConsoleMode(Console, ConsoleMode & ~ENABLE_ECHO_INPUT); | ||||||
|  |  | ||||||
|  | 		const char Result = Input(); | ||||||
|  |  | ||||||
|  | 		SetConsoleMode(Console, ConsoleMode); | ||||||
|  |  | ||||||
|  | 		return Result; | ||||||
|  | 	} | ||||||
|  | #	elif PLATFORM_LINUX | ||||||
|  | 	{ } | ||||||
|  | #	endif | ||||||
|  |  | ||||||
|  | 	return static_cast<char>(-1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | FString InputLn(bool bEcho) | ||||||
|  | { | ||||||
|  | 	if (bEcho || IsOutputRedirected()) | ||||||
|  | 	{ | ||||||
|  | 		FString Result; | ||||||
|  |  | ||||||
|  | 		while (true) | ||||||
|  | 		{ | ||||||
|  | 			const int Char = std::getchar(); | ||||||
|  |  | ||||||
|  | 			if (Char == EOF || Char == '\n') break; | ||||||
|  |  | ||||||
|  | 			Result.PushBack(static_cast<char>(Char)); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return Result; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | #	if PLATFORM_WINDOWS | ||||||
|  | 	{ | ||||||
|  | 		const HANDLE Console = GetStdHandle(STD_INPUT_HANDLE); | ||||||
|  |  | ||||||
|  | 		if (Console == INVALID_HANDLE_VALUE) return ""; | ||||||
|  |  | ||||||
|  | 		DWORD ConsoleMode = 0; | ||||||
|  |  | ||||||
|  | 		GetConsoleMode(Console, &ConsoleMode); | ||||||
|  |  | ||||||
|  | 		SetConsoleMode(Console, ConsoleMode & ~ENABLE_ECHO_INPUT); | ||||||
|  |  | ||||||
|  | 		const FString Result = InputLn(); | ||||||
|  |  | ||||||
|  | 		SetConsoleMode(Console, ConsoleMode); | ||||||
|  |  | ||||||
|  | 		return Result; | ||||||
|  | 	} | ||||||
|  | #	elif PLATFORM_LINUX | ||||||
|  | 	{ } | ||||||
|  | #	endif | ||||||
|  |  | ||||||
|  | 	return ""; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool Print(char Char) | ||||||
|  | { | ||||||
|  | 	return std::putchar(Char) != EOF; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool Error(char Char) | ||||||
|  | { | ||||||
|  | 	return std::fputc(Char, stderr) != EOF; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NAMESPACE_MODULE_END(Utility) | ||||||
|  | NAMESPACE_MODULE_END(Redcraft) | ||||||
|  | NAMESPACE_REDCRAFT_END | ||||||
							
								
								
									
										217
									
								
								Redcraft.Utility/Source/Public/Miscellaneous/Console.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								Redcraft.Utility/Source/Public/Miscellaneous/Console.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,217 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "CoreTypes.h" | ||||||
|  | #include "TypeTraits/TypeTraits.h" | ||||||
|  | #include "Templates/Utility.h" | ||||||
|  | #include "Iterators/Utility.h" | ||||||
|  | #include "Strings/Formatting.h" | ||||||
|  | #include "Strings/StringView.h" | ||||||
|  | #include "Strings/String.h" | ||||||
|  | #include "Miscellaneous/BitwiseEnum.h" | ||||||
|  |  | ||||||
|  | NAMESPACE_REDCRAFT_BEGIN | ||||||
|  | NAMESPACE_MODULE_BEGIN(Redcraft) | ||||||
|  | NAMESPACE_MODULE_BEGIN(Utility) | ||||||
|  |  | ||||||
|  | /** An enumeration that defines the color of the console. */ | ||||||
|  | enum class EColor : uint8 | ||||||
|  | { | ||||||
|  | 	Default = 0xFF, | ||||||
|  |  | ||||||
|  | 	Black     = 0b0000, | ||||||
|  | 	Red       = 0b0001, | ||||||
|  | 	Green     = 0b0010, | ||||||
|  | 	Blue      = 0b0100, | ||||||
|  | 	Intensity = 0b1000, | ||||||
|  |  | ||||||
|  | 	Cyan    = Green | Blue, | ||||||
|  | 	Magenta = Blue  | Red, | ||||||
|  | 	Yellow  = Red   | Green, | ||||||
|  |  | ||||||
|  | 	White = Red | Green | Blue, | ||||||
|  |  | ||||||
|  | 	BrightBlack   = Intensity | Black, | ||||||
|  | 	BrightRed     = Intensity | Red, | ||||||
|  | 	BrightGreen   = Intensity | Green, | ||||||
|  | 	BrightBlue    = Intensity | Blue, | ||||||
|  | 	BrightYellow  = Intensity | Yellow, | ||||||
|  | 	BrightMagenta = Intensity | Magenta, | ||||||
|  | 	BrightCyan    = Intensity | Cyan, | ||||||
|  | 	BrightWhite   = Intensity | White | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | ENABLE_ENUM_CLASS_BITWISE_OPERATIONS(EColor) | ||||||
|  |  | ||||||
|  | /** @return The color of the console. */ | ||||||
|  | NODISCARD REDCRAFTUTILITY_API EColor GetForegroundColor(); | ||||||
|  | NODISCARD REDCRAFTUTILITY_API EColor GetBackgroundColor(); | ||||||
|  |  | ||||||
|  | /** Set the color of the console. Returns the color that was successfully set. */ | ||||||
|  | REDCRAFTUTILITY_API EColor SetForegroundColor(EColor InColor); | ||||||
|  | REDCRAFTUTILITY_API EColor SetBackgroundColor(EColor InColor); | ||||||
|  |  | ||||||
|  | /** @return The size of the console window. */ | ||||||
|  | NODISCARD REDCRAFTUTILITY_API uint GetWindowWidth(); | ||||||
|  | NODISCARD REDCRAFTUTILITY_API uint GetWindowHeight(); | ||||||
|  |  | ||||||
|  | /** @return true if the standard stream is redirected. */ | ||||||
|  | NODISCARD REDCRAFTUTILITY_API bool IsInputRedirected(); | ||||||
|  | NODISCARD REDCRAFTUTILITY_API bool IsOutputRedirected(); | ||||||
|  | NODISCARD REDCRAFTUTILITY_API bool IsErrorRedirected(); | ||||||
|  |  | ||||||
|  | /** Clear the console screen. */ | ||||||
|  | REDCRAFTUTILITY_API void Clear(); | ||||||
|  |  | ||||||
|  | /** @return The input character from the standard input. */ | ||||||
|  | NODISCARD REDCRAFTUTILITY_API char Input(bool bEcho = true); | ||||||
|  |  | ||||||
|  | /** @return The input line from the standard input. */ | ||||||
|  | NODISCARD REDCRAFTUTILITY_API FString InputLn(bool bEcho = true); | ||||||
|  |  | ||||||
|  | /** Print the character to the standard output. */ | ||||||
|  | REDCRAFTUTILITY_API bool Print(char Char); | ||||||
|  |  | ||||||
|  | /** Print the formatted string to the standard output. */ | ||||||
|  | template <CFormattable... Ts> | ||||||
|  | FORCEINLINE bool Print(FStringView Fmt, Ts&&... Args) | ||||||
|  | { | ||||||
|  | 	struct FStandardOutputIterator | ||||||
|  | 	{ | ||||||
|  | 		FORCEINLINE constexpr FStandardOutputIterator& operator=(char Char) | ||||||
|  | 		{ | ||||||
|  | 			bError |= !Print(Char); | ||||||
|  | 			return *this; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		FORCEINLINE constexpr bool operator==(FDefaultSentinel) const { return bError; } | ||||||
|  |  | ||||||
|  | 		FORCEINLINE constexpr FStandardOutputIterator& operator*()     { return *this; } | ||||||
|  | 		FORCEINLINE constexpr FStandardOutputIterator& operator++()    { return *this; } | ||||||
|  | 		FORCEINLINE constexpr FStandardOutputIterator& operator++(int) { return *this; } | ||||||
|  |  | ||||||
|  | 		bool bError = false; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	static_assert(COutputIterator<FStandardOutputIterator, char>); | ||||||
|  |  | ||||||
|  | 	FStandardOutputIterator Iter; | ||||||
|  |  | ||||||
|  | 	auto Range = Ranges::View(Iter, DefaultSentinel); | ||||||
|  |  | ||||||
|  | 	Iter = Algorithms::Format(Range, Fmt, Forward<Ts>(Args)...); | ||||||
|  |  | ||||||
|  | 	return Iter != DefaultSentinel; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** Print the value to the standard output. */ | ||||||
|  | template <CFormattable T> | ||||||
|  | FORCEINLINE bool Print(T&& Value) | ||||||
|  | { | ||||||
|  | 	if constexpr (CSameAs<TRemoveCVRef<T>, char>) | ||||||
|  | 	{ | ||||||
|  | 		return Print(static_cast<char>(Value)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	else if constexpr (CConvertibleTo<T, FStringView>) | ||||||
|  | 	{ | ||||||
|  | 		return Print(static_cast<FStringView>(Value)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	else return Print(TEXT("{0}"), Forward<T>(Value)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** Print the newline character to the standard output. */ | ||||||
|  | FORCEINLINE bool PrintLn() | ||||||
|  | { | ||||||
|  | 	return Print(TEXT("\n")); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** Print the string to the standard output and append the newline character. */ | ||||||
|  | template <CFormattable... Ts> | ||||||
|  | FORCEINLINE bool PrintLn(FStringView Fmt, Ts&&... Args) | ||||||
|  | { | ||||||
|  | 	return Print(Fmt, Forward<Ts>(Args)...) && Print(TEXT("\n")); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** Print the value to the standard output and append the newline character. */ | ||||||
|  | template <CFormattable T> | ||||||
|  | FORCEINLINE bool PrintLn(T&& Value) | ||||||
|  | { | ||||||
|  | 	return Print(Forward<T>(Value)) && Print(TEXT("\n")); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** Print the character to the standard error. */ | ||||||
|  | REDCRAFTUTILITY_API bool Error(char Char); | ||||||
|  |  | ||||||
|  | /** Print the formatted string to the standard error. */ | ||||||
|  | template <CFormattable... Ts> | ||||||
|  | FORCEINLINE bool Error(FStringView Fmt, Ts&&... Args) | ||||||
|  | { | ||||||
|  | 	struct FStandardOutputIterator | ||||||
|  | 	{ | ||||||
|  | 		FORCEINLINE constexpr FStandardOutputIterator& operator=(char Char) | ||||||
|  | 		{ | ||||||
|  | 			bError |= !Error(Char); | ||||||
|  | 			return *this; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		FORCEINLINE constexpr bool operator==(FDefaultSentinel) const { return bError; } | ||||||
|  |  | ||||||
|  | 		FORCEINLINE constexpr FStandardOutputIterator& operator*()     { return *this; } | ||||||
|  | 		FORCEINLINE constexpr FStandardOutputIterator& operator++()    { return *this; } | ||||||
|  | 		FORCEINLINE constexpr FStandardOutputIterator& operator++(int) { return *this; } | ||||||
|  |  | ||||||
|  | 		bool bError = false; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	static_assert(COutputIterator<FStandardOutputIterator, char>); | ||||||
|  |  | ||||||
|  | 	FStandardOutputIterator Iter; | ||||||
|  |  | ||||||
|  | 	auto Range = Ranges::View(Iter, DefaultSentinel); | ||||||
|  |  | ||||||
|  | 	Iter = Algorithms::Format(Range, Fmt, Forward<Ts>(Args)...); | ||||||
|  |  | ||||||
|  | 	return Iter != DefaultSentinel; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** Print the value to the standard error. */ | ||||||
|  | template <CFormattable T> | ||||||
|  | FORCEINLINE bool Error(T&& Value) | ||||||
|  | { | ||||||
|  | 	if constexpr (CSameAs<TRemoveCVRef<T>, char>) | ||||||
|  | 	{ | ||||||
|  | 		return Error(static_cast<char>(Value)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	else if constexpr (CConvertibleTo<T, FStringView>) | ||||||
|  | 	{ | ||||||
|  | 		return Error(static_cast<FStringView>(Value)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	else return Error(TEXT("{0}"), Forward<T>(Value)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** Print the newline character to the standard error. */ | ||||||
|  | FORCEINLINE bool ErrorLn() | ||||||
|  | { | ||||||
|  | 	return Error(TEXT("\n")); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** Print the string to the standard error and append the newline character. */ | ||||||
|  | template <CFormattable... Ts> | ||||||
|  | FORCEINLINE bool ErrorLn(FStringView Fmt, Ts&&... Args) | ||||||
|  | { | ||||||
|  | 	return Error(Fmt, Forward<Ts>(Args)...) && Error(TEXT("\n")); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** Print the value to the standard error and append the newline character. */ | ||||||
|  | template <CFormattable T> | ||||||
|  | FORCEINLINE bool ErrorLn(T&& Value) | ||||||
|  | { | ||||||
|  | 	return Error(Forward<T>(Value)) && Error(TEXT("\n")); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NAMESPACE_MODULE_END(Utility) | ||||||
|  | NAMESPACE_MODULE_END(Redcraft) | ||||||
|  | NAMESPACE_REDCRAFT_END | ||||||
		Reference in New Issue
	
	Block a user