mirror of
https://github.com/thunderbrewhq/thunderbrew
synced 2025-10-30 15:56:04 +03:00
410 lines
9.5 KiB
C++
410 lines
9.5 KiB
C++
|
|
#include "console/Console.hpp"
|
|
#include "console/Highlight.hpp"
|
|
#include "console/Line.hpp"
|
|
#include "console/Command.hpp"
|
|
#include "console/Text.hpp"
|
|
#include "console/Screen.hpp"
|
|
#include "gx/Device.hpp"
|
|
#include "os/Clipboard.hpp"
|
|
#include <bc/Memory.hpp>
|
|
#include <storm/Thread.hpp>
|
|
#include <cstdarg>
|
|
#include <cstdio>
|
|
|
|
int32_t s_historyIndex = 0;
|
|
// in this list
|
|
// head = the input line
|
|
// tail = the oldest line
|
|
STORM_LIST(CONSOLELINE) s_linelist;
|
|
CONSOLELINE* s_currlineptr;
|
|
uint32_t s_NumLines = 0;
|
|
SCritSect s_critsect;
|
|
|
|
void CONSOLELINE::Up() {
|
|
if ((ConsoleCommandHistoryDepth() - 1) == s_historyIndex) {
|
|
return;
|
|
}
|
|
|
|
auto previous = ConsoleCommandHistory(s_historyIndex + 1);
|
|
|
|
if (previous) {
|
|
MakeCommandCurrent(this, previous);
|
|
s_historyIndex++;
|
|
SetInputString(this->buffer);
|
|
}
|
|
}
|
|
|
|
void CONSOLELINE::Down() {
|
|
if (s_historyIndex == -1) {
|
|
return;
|
|
}
|
|
|
|
const char* next;
|
|
|
|
if (s_historyIndex == 0) {
|
|
next = "";
|
|
} else {
|
|
if (!(next = ConsoleCommandHistory(s_historyIndex - 1))) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
MakeCommandCurrent(this, next);
|
|
s_historyIndex--;
|
|
SetInputString(this->buffer);
|
|
}
|
|
|
|
void CONSOLELINE::Delete() {
|
|
if (this->inputpos > this->chars) {
|
|
return;
|
|
}
|
|
|
|
auto pos = this->inputpos;
|
|
memmove(this->buffer + pos, this->buffer + pos + 1, this->chars - pos);
|
|
this->chars--;
|
|
SetInputString(this->buffer);
|
|
}
|
|
|
|
void CONSOLELINE::Backspace() {
|
|
auto pos = this->inputpos;
|
|
|
|
if (this->inputstart >= pos) {
|
|
return;
|
|
}
|
|
|
|
if (pos < this->chars) {
|
|
memmove(this->buffer + pos - 1, this->buffer + pos, (this->chars - pos) + 1);
|
|
} else {
|
|
this->buffer[pos - 1] = '\0';
|
|
}
|
|
|
|
this->inputpos--;
|
|
this->chars--;
|
|
SetInputString(this->buffer);
|
|
}
|
|
|
|
CONSOLELINE::~CONSOLELINE() {
|
|
if (this->buffer) {
|
|
FREE(this->buffer);
|
|
}
|
|
|
|
if (this->fontPointer) {
|
|
GxuFontDestroyString(this->fontPointer);
|
|
}
|
|
}
|
|
|
|
void GenerateNodeString(CONSOLELINE* node) {
|
|
auto font = TextBlockGetFontPtr(s_textFont);
|
|
|
|
if (font && node && node->buffer && node->buffer[0] != '\0') {
|
|
if (node->fontPointer) {
|
|
GxuFontDestroyString(node->fontPointer);
|
|
}
|
|
|
|
C3Vector pos = {
|
|
0.0f, 0.0f, 1.0f
|
|
};
|
|
|
|
GxuFontCreateString(
|
|
font,
|
|
node->buffer,
|
|
s_fontHeight,
|
|
pos,
|
|
1.0f,
|
|
s_fontHeight,
|
|
0.0f,
|
|
node->fontPointer,
|
|
GxVJ_Middle, GxHJ_Left,
|
|
s_baseTextFlags,
|
|
s_colorArray[node->colorType],
|
|
s_charSpacing,
|
|
1.0f);
|
|
|
|
STORM_ASSERT(node->fontPointer);
|
|
}
|
|
}
|
|
|
|
void SetInputString(const char* buffer) {
|
|
if (s_inputString) {
|
|
GxuFontDestroyString(s_inputString);
|
|
}
|
|
s_inputString = nullptr;
|
|
|
|
if (buffer && buffer[0] != '\0') {
|
|
C3Vector pos = { 0.0f, 0.0f, 1.0f };
|
|
|
|
auto font = TextBlockGetFontPtr(s_textFont);
|
|
|
|
GxuFontCreateString(
|
|
font,
|
|
buffer,
|
|
s_fontHeight,
|
|
pos,
|
|
1.0f,
|
|
s_fontHeight,
|
|
0.0f,
|
|
s_inputString,
|
|
GxVJ_Middle, GxHJ_Left,
|
|
s_baseTextFlags,
|
|
s_colorArray[INPUT_COLOR],
|
|
s_charSpacing,
|
|
1.0f);
|
|
}
|
|
}
|
|
|
|
void ReserveInputSpace(CONSOLELINE* line, uint32_t chars) {
|
|
size_t newsize = line->chars + chars;
|
|
if (newsize >= line->charsalloc) {
|
|
while (line->charsalloc <= newsize) {
|
|
line->charsalloc += CONSOLE_LINE_EXTRA_BYTES;
|
|
}
|
|
|
|
auto buffer = reinterpret_cast<char*>(ALLOC(line->charsalloc));
|
|
SStrCopy(buffer, line->buffer, line->charsalloc);
|
|
FREE(line->buffer);
|
|
line->buffer = buffer;
|
|
}
|
|
}
|
|
|
|
void MoveLinePtr(int32_t direction, int32_t modifier) {
|
|
auto lineptr = s_currlineptr;
|
|
|
|
if (modifier == 1) {
|
|
for (int32_t i = 0; i < 10 && lineptr != nullptr; i++) {
|
|
lineptr = direction == 1 ? lineptr->m_link.Next() : lineptr->m_link.Prev();
|
|
}
|
|
} else {
|
|
lineptr = direction == 1 ? lineptr->m_link.Next() : lineptr->m_link.Prev();
|
|
}
|
|
|
|
if (lineptr) {
|
|
s_currlineptr = lineptr;
|
|
}
|
|
}
|
|
|
|
void MakeCommandCurrent(CONSOLELINE* lineptr, const char* command) {
|
|
auto len = lineptr->inputstart;
|
|
lineptr->inputpos = len;
|
|
lineptr->chars = len;
|
|
lineptr->buffer[len] = '\0';
|
|
|
|
len = SStrLen(command);
|
|
ReserveInputSpace(lineptr, len);
|
|
|
|
SStrCopy(lineptr->buffer + lineptr->inputpos, command, STORM_MAX_STR);
|
|
|
|
len = lineptr->inputpos + len;
|
|
lineptr->inputpos = len;
|
|
lineptr->chars = len;
|
|
}
|
|
|
|
void EnforceMaxLines() {
|
|
if (s_NumLines <= CONSOLE_LINES_MAX) {
|
|
return;
|
|
}
|
|
|
|
// Pop oldest line off the list
|
|
auto lineptr = s_linelist.Tail();
|
|
if (lineptr == s_currlineptr) {
|
|
s_currlineptr = lineptr->Prev();
|
|
}
|
|
|
|
// Clean up oldest line
|
|
s_linelist.DeleteNode(lineptr);
|
|
|
|
s_NumLines--;
|
|
}
|
|
|
|
CONSOLELINE* GetInputLine() {
|
|
auto head = s_linelist.Head();
|
|
|
|
// If the list is empty, or the list's head is an entered input-line,
|
|
// Create a fresh input line, with "> " prefixed before the caret
|
|
if (head && head->inputpos != 0) {
|
|
return head;
|
|
}
|
|
|
|
auto line = NEW(CONSOLELINE);
|
|
line->buffer = reinterpret_cast<char*>(ALLOC(CONSOLE_LINE_EXTRA_BYTES));
|
|
line->charsalloc = CONSOLE_LINE_EXTRA_BYTES;
|
|
|
|
s_linelist.LinkToHead(line);
|
|
s_NumLines++;
|
|
|
|
SStrCopy(line->buffer, "> ", line->charsalloc);
|
|
SetInputString(line->buffer);
|
|
auto chars = SStrLen(line->buffer);
|
|
line->inputstart = chars;
|
|
line->inputpos = chars;
|
|
line->chars = chars;
|
|
line->colorType = INPUT_COLOR;
|
|
|
|
s_currlineptr = line;
|
|
|
|
EnforceMaxLines();
|
|
|
|
return line;
|
|
}
|
|
|
|
CONSOLELINE* GetLineAtMousePosition(float y) {
|
|
// Loop through linelist to find line at mouse position
|
|
auto linePos = static_cast<int32_t>((s_consoleHeight - (1.0 - y)) / s_fontHeight);
|
|
|
|
if (linePos == 1) {
|
|
return s_linelist.Head();
|
|
}
|
|
|
|
if (s_currlineptr != s_linelist.Head()) {
|
|
linePos--;
|
|
}
|
|
|
|
auto line = s_currlineptr;
|
|
|
|
while (linePos > 1) {
|
|
linePos--;
|
|
|
|
if (!line) {
|
|
line = s_linelist.Head();
|
|
}
|
|
|
|
if (line == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
line = line->Next();
|
|
}
|
|
|
|
return line;
|
|
}
|
|
|
|
void PasteInInputLine(const char* characters) {
|
|
auto len = SStrLen(characters);
|
|
|
|
if (!len) {
|
|
return;
|
|
}
|
|
|
|
auto line = GetInputLine();
|
|
|
|
ReserveInputSpace(line, len);
|
|
|
|
if (line->inputpos < line->chars) {
|
|
if (len <= 1) {
|
|
memmove(&line->buffer[line->inputpos + 1], &line->buffer[line->inputpos], line->chars - (line->inputpos + 1));
|
|
|
|
line->buffer[line->inputpos] = *characters;
|
|
|
|
line->inputpos++;
|
|
line->chars++;
|
|
} else {
|
|
auto input = reinterpret_cast<char*>(ALLOC(line->charsalloc));
|
|
SStrCopy(input, &line->buffer[line->inputpos], STORM_MAX_STR);
|
|
|
|
auto buffer = reinterpret_cast<char*>(ALLOC(line->charsalloc));
|
|
SStrCopy(buffer, line->buffer, STORM_MAX_STR);
|
|
buffer[line->inputpos] = '\0';
|
|
|
|
SStrPack(buffer, characters, line->charsalloc);
|
|
|
|
auto len = SStrLen(buffer);
|
|
|
|
line->inputpos = len;
|
|
|
|
SStrPack(buffer, input, line->charsalloc);
|
|
SStrCopy(line->buffer, buffer, STORM_MAX_STR);
|
|
|
|
line->chars = SStrLen(line->buffer);
|
|
|
|
if (input) {
|
|
FREE(input);
|
|
}
|
|
|
|
if (buffer) {
|
|
FREE(buffer);
|
|
}
|
|
}
|
|
} else {
|
|
for (int32_t i = 0; i < len; i++) {
|
|
line->buffer[line->inputpos++] = characters[i];
|
|
}
|
|
|
|
line->buffer[line->inputpos] = '\0';
|
|
line->chars = line->inputpos;
|
|
}
|
|
|
|
SetInputString(line->buffer);
|
|
}
|
|
|
|
void ConsoleWrite(const char* str, COLOR_T color) {
|
|
if (!str || !*str || !GxDevExists() || !s_textFont) {
|
|
return;
|
|
}
|
|
|
|
s_critsect.Enter();
|
|
|
|
auto lineptr = NEW(CONSOLELINE);
|
|
auto head = s_linelist.Head();
|
|
if (head == nullptr || head->inputpos == 0) {
|
|
// Attach console line to head
|
|
s_linelist.LinkToHead(lineptr);
|
|
} else {
|
|
// Attach console line between head and head-1
|
|
s_linelist.LinkNode(lineptr, 1, head->Prev());
|
|
}
|
|
|
|
size_t len = SStrLen(str) + 1;
|
|
lineptr->chars = len;
|
|
lineptr->charsalloc = len;
|
|
lineptr->buffer = reinterpret_cast<char*>(ALLOC(len));
|
|
lineptr->colorType = color;
|
|
SStrCopy(lineptr->buffer, str, STORM_MAX_STR);
|
|
|
|
GenerateNodeString(lineptr);
|
|
|
|
s_NumLines++;
|
|
EnforceMaxLines();
|
|
|
|
s_critsect.Leave();
|
|
}
|
|
|
|
void ConsolePrintf(const char* str, ...) {
|
|
char buffer[1024] = {0};
|
|
|
|
if (str != nullptr && str[0] != '\0') {
|
|
va_list list;
|
|
va_start(list, str);
|
|
vsnprintf(buffer, sizeof(buffer), str, list);
|
|
va_end(list);
|
|
|
|
ConsoleWrite(buffer, DEFAULT_COLOR);
|
|
}
|
|
}
|
|
|
|
void ConsoleWriteA(const char* str, COLOR_T color, ...) {
|
|
char buffer[1024] = {0};
|
|
|
|
if (str != nullptr && str[0] != '\0') {
|
|
va_list list;
|
|
va_start(list, color);
|
|
vsnprintf(buffer, sizeof(buffer), str, list);
|
|
va_end(list);
|
|
|
|
ConsoleWrite(buffer, color);
|
|
}
|
|
}
|
|
|
|
void PasteClipboardInInputLine() {
|
|
auto str = OsClipboardGetString();
|
|
if (str) {
|
|
PasteInInputLine(str);
|
|
FREE(str);
|
|
ResetHighlight();
|
|
}
|
|
}
|
|
|
|
void ConsoleClear() {
|
|
s_NumLines = 0;
|
|
s_linelist.Clear();
|
|
}
|