/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: ConsoleTTY.Unix.cpp Date: 2022-5-2 Author: Reece ***/ #include #include "../Console.hpp" #include "ConsoleTTY.Unix.hpp" #include "../ColorConvert.hpp" #include #include namespace Aurora::Console::ConsoleTTY { static int gFdTtyHandle {-1}; static bool gIsBuffering = false; bool IsBuffering() { return gIsBuffering; } void BeginBuffering() { ConsoleStd::Lock(); gIsBuffering = true; } bool EndBuffering() { ConsoleStd::Unlock(); gIsBuffering = false; //TODO (Reece): Was signal handler called? return true; } static void TTYWrite(const AuString &in) { if (in.empty()) { return; } auto written = ConsoleStd::WriteStdOutBlocking2(in.data(), in.size()); SysAssert(written == in.size(), "TTY Buffer Full"); } AUKN_SYM void TTYClearLine(EAnsiColor bgColor) { TTYWrite(kAnsiColorBackgroundToVirtualEscape[AuStaticCast(bgColor)] + "\033[2K" + kAnsiColorBackgroundToVirtualEscape[AuStaticCast(EAnsiColor::eReset)]); } AUKN_SYM void TTYClearScreen() { TTYWrite("\033[H\033[J"); } AUKN_SYM void TTYFill(char character, EAnsiColor fgColor, EAnsiColor bgColor) { if (character == ' ') { TTYWrite(kAnsiColorBackgroundToVirtualEscape[AuStaticCast(bgColor)] + "\033[H\033[J" + kAnsiColorBackgroundToVirtualEscape[AuStaticCast(EAnsiColor::eReset)]); } else { TTYWrite(kAnsiColorBackgroundToVirtualEscape[AuStaticCast(bgColor)] + "\033[2J" + kAnsiColorForegroundToVirtualEscape[AuStaticCast(fgColor)]); auto size = TTYScreenSize(); AuString line(size.first + 1, character); line[line.size() - 1] = '\n'; if (size.second) { for (int i = 0; i < size.second - 1; i++) { TTYWrite(line); } line.pop_back(); TTYWrite(line); } TTYWrite(kAnsiColorForegroundToVirtualEscape[AuStaticCast(EAnsiColor::eReset)] + kAnsiColorBackgroundToVirtualEscape[AuStaticCast(EAnsiColor::eReset)]); } } AUKN_SYM AuUInt32 TTYWrite(const void *buffer, AuUInt32 length) { if (!length) { return 0; } return ConsoleStd::WriteStdOutBlocking2(buffer, length); } AUKN_SYM void TTYWrite(const char *string, EAnsiColor fgColor, EAnsiColor bgColor) { AuString imtired; if (!string) { return; } if (fgColor != EAnsiColor::eEnumCount) { imtired = kAnsiColorForegroundToVirtualEscape[AuStaticCast(fgColor)]; } if (bgColor != EAnsiColor::eEnumCount) { imtired += kAnsiColorBackgroundToVirtualEscape[AuStaticCast(bgColor)]; } TTYWrite(imtired); auto len = strlen(string); if (!len) { return; } if (string[len - 1] == '\n') { TTYWrite(string, len -1); } else { TTYWrite(string, len); } imtired = kAnsiColorForegroundToVirtualEscape[AuStaticCast(EAnsiColor::eReset)]; //imtired += kAnsiColorBackgroundToVirtualEscape[AuStaticCast(EAnsiColor::eReset)]; if (string[len - 1] == '\n') { imtired += '\n'; } TTYWrite(imtired); } AUKN_SYM void TTYReturnHome() { TTYWrite("\033[H"); } AUKN_SYM AuPair TTYScreenSize() { struct winsize ws; if (::ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != 0) { return {1200, 640}; } return AuMakePair(AuStaticCast(ws.ws_col), AuStaticCast(ws.ws_row)); } static void ForceFlush() { ConsoleStd::Flush(); } AUKN_SYM void TTYStorePos() { TTYWrite("\0337"); ForceFlush(); } AUKN_SYM void TTYRestorePos() { TTYWrite("\0338"); ForceFlush(); } AUKN_SYM void TTYMoveY(AuInt16 lines) { if (lines == 0) { return; } if (lines > 0) { TTYWrite(fmt::format("\033[{:0}A", lines)); } else { TTYWrite(fmt::format("\033[{:0}B", 0 - lines)); } } AUKN_SYM void TTYMoveX(AuInt16 lines) { if (lines == 0) { return; } if (lines > 0) { TTYWrite(fmt::format("\033[{:0}C", lines)); } else { TTYWrite(fmt::format("\033[{:0}D", 0 - lines)); } } AUKN_SYM void TTYSetY(AuUInt16 Y) { TTYWrite(fmt::format("\033[{:0}G", Y + 1)); } AUKN_SYM void TTYSetX(AuUInt16 X) { TTYWrite(fmt::format("\033[{:0}d", X + 1)); } AUKN_SYM void TTYSetPos(AuPair position) { TTYWrite(fmt::format("\033[{:1};{:0}H", position.second + 1, position.first + 1)); } AUKN_SYM void TTYScrollBuffer(int Y) { if (Y == 0) { return; } if (Y) { TTYWrite(fmt::format("\033[{:0}S", Y)); } else { TTYWrite(fmt::format("\033[{:0}T", 0 - Y)); } } void InitUnix() { // TODO: consider capturing the signal to update a global row/cols variable // TODO: consider opening /dev/tty instead of using stdout handle } void DeinitUnix() { if ((gFdTtyHandle != 0) && (gFdTtyHandle != -1)) { ::close(AuExchange(gFdTtyHandle, -1)); } } }