#include #include #include "../src/Parser/Lexer/Lexer.hpp" #include "../src/Parser/Parser.hpp" #include "../src/Parser/Statements/ParsedStatementStringifier.hpp" void UpdateScriptWithParseInfo(WINDOW* inputWindow, const std::u8string& script, const MalachScript::Diagnostics::Diagnostic* diag, [[maybe_unused]] const MalachScript::Parser::LexToken* firstToken) { std::stringstream ss((char*)script.c_str()); int col; int row; getyx(inputWindow, row, col); wclear(inputWindow); if (diag != nullptr) { auto start = diag->GetSpan().GetStart(); auto end = diag->GetSpan().GetEnd() + 1; if (end > script.size()) { end = script.size(); if (start == end && start > 0) { start--; } } waddnstr(inputWindow, (char*)script.c_str(), start); wattron(inputWindow, COLOR_PAIR(1)); waddnstr(inputWindow, (char*)script.substr(start).data(), end - start); wattroff(inputWindow, COLOR_PAIR(1)); waddnstr(inputWindow, (char*)script.substr(end).data(), script.size() - end); if (start >= script.size() - 1) { wattron(inputWindow, COLOR_PAIR(1)); waddch(inputWindow, ' '); wattroff(inputWindow, COLOR_PAIR(1)); } } else { waddstr(inputWindow, (char*)script.c_str()); } wmove(inputWindow, row, col); wrefresh(inputWindow); } void ParseAndUpdate(const std::vector lines, WINDOW* diagnosticsWindow, WINDOW* parsedWindow, WINDOW* inputWindow) { std::u8string script; for (const auto& line : lines) { script += line; script += '\n'; } auto logger = MalachScript::Diagnostics::Logger(); auto lexer = MalachScript::Parser::Lexer(u8"diag", script, &logger); const auto* firstToken = lexer.Lex(); [[maybe_unused]] const auto* parsedResult = MalachScript::Parser::Parser::Parse(firstToken, u8"diag", &logger); const MalachScript::Diagnostics::Diagnostic* diag = nullptr; wclear(diagnosticsWindow); if (!logger.GetMessages().empty()) { diag = &logger.GetMessages()[0]; wattron(diagnosticsWindow, COLOR_PAIR(1)); waddch(diagnosticsWindow, '['); waddstr(diagnosticsWindow, "Error"); waddch(diagnosticsWindow, ']'); wattroff(diagnosticsWindow, COLOR_PAIR(1)); waddch(diagnosticsWindow, ' '); waddstr(diagnosticsWindow, std::to_string(diag->GetSpan().GetStart() + 1).c_str()); waddch(diagnosticsWindow, '-'); waddstr(diagnosticsWindow, std::to_string(diag->GetSpan().GetEnd() + 1).c_str()); waddch(diagnosticsWindow, ' '); waddstr(diagnosticsWindow, MalachScript::Diagnostics::DiagnosticTypeHelper::ToEnglishString(diag->GetType()).c_str()); waddch(diagnosticsWindow, '\n'); } wrefresh(diagnosticsWindow); wclear(parsedWindow); if (logger.GetMessages().empty()) { std::stringstream ss; MalachScript::Parser::ParsedStatementStringifier::Stringify(parsedResult, ss, "", true); waddstr(parsedWindow, ss.str().c_str()); } wrefresh(parsedWindow); UpdateScriptWithParseInfo(inputWindow, script, diag, firstToken); } int main([[maybe_unused]] int argc, [[maybe_unused]] const char* argv[]) { setlocale(LC_ALL, ""); initscr(); cbreak(); noecho(); keypad(stdscr, true); set_tabsize(4); start_color(); init_pair(1, COLOR_BLACK, COLOR_RED); clear(); int maxX; int maxY; getmaxyx(stdscr, maxY, maxX); wresize(stdscr, maxY, maxX); wrefresh(stdscr); const int inputFieldSize = 30; wborder(stdscr, 0, 0, 0, 0, 0, 0, 0, 0); wmove(stdscr, 31, 1); whline(stdscr, ACS_HLINE, maxX - 2); wmove(stdscr, 32, maxX / 2); wvline(stdscr, ACS_VLINE, 25); wrefresh(stdscr); auto* inputWindow = newwin(inputFieldSize, maxX - 3, 1, 2); keypad(inputWindow, true); auto* diagnosticsWindow = newwin(25, (maxX - 4) / 2, 32, 2); auto* parsedResultWindow = newwin(25, (maxX - 4) / 2 - 2, 32, (maxX - 4) / 2 + 4); wrefresh(parsedResultWindow); int row = 0; int col = 0; // Special handler so we can keep the column int rightPos = 0; std::vector lines = {u8""}; int c; bool running = true; while (running) { c = wgetch(inputWindow); switch (c) { case 27: running = false; break; case KEY_LEFT: { if (col > 0) { wmove(inputWindow, row, --col); rightPos = col; } break; } case KEY_RIGHT: { auto& line = lines[row]; if (col < (int)line.size()) { wmove(inputWindow, row, ++col); rightPos = col; } break; } case KEY_UP: if (row > 0) { col = rightPos; if (col > (int)lines[row - 1].size()) { col = (int)lines[row - 1].size(); } wmove(inputWindow, --row, col); } wrefresh(stdscr); break; case KEY_DOWN: if (row < (int)lines.size() - 1) { col = rightPos; if (col > (int)lines[row + 1].size()) { col = (int)lines[row + 1].size(); } wmove(inputWindow, ++row, col); } break; case KEY_BACKSPACE: case 127: if (col > 0) { mvwdelch(inputWindow, row, --col); auto& line = lines[row]; line = line.erase(col, 1); ParseAndUpdate(lines, diagnosticsWindow, parsedResultWindow, inputWindow); } break; case 10: case KEY_ENTER: lines.insert(lines.begin() + row + 1, u8""); row++; col = 0; for (size_t i = row - 1; i < lines.size(); i++) { wmove(inputWindow, i, 0); wclrtoeol(inputWindow); waddstr(inputWindow, (char*)lines[i].c_str()); } wmove(inputWindow, row, col); break; case 9: case KEY_STAB: { wmove(inputWindow, row, 0); wclrtoeol(inputWindow); auto& line = lines[row]; if ((int)line.length() <= col) { line += u8" "; } else { for (size_t i = 0; i < 4; i++) { line.insert(line.begin() + col, u8' '); } } waddstr(inputWindow, (char*)line.c_str()); col += 4; rightPos = col; wmove(inputWindow, row, col); ParseAndUpdate(lines, diagnosticsWindow, parsedResultWindow, inputWindow); break; } case KEY_END: { col = lines[row].size(); rightPos = col; wmove(inputWindow, row, col); break; } case KEY_HOME: { col = 0; rightPos = col; wmove(inputWindow, row, col); break; } default: { wmove(inputWindow, row, 0); auto& line = lines[row]; if ((int)line.length() <= col) { line += (char8_t)c; } else { line.insert(line.begin() + col, c); } waddstr(inputWindow, (char*)line.c_str()); col++; rightPos = col; wmove(inputWindow, row, col); ParseAndUpdate(lines, diagnosticsWindow, parsedResultWindow, inputWindow); break; } } wrefresh(inputWindow); } endwin(); return EXIT_SUCCESS; }