#include #include #include "calculator.cpp" #include "commands.cpp" #include "cursor.cpp" #include "debug.cpp" #include "getch.h" #include "terminal.cpp" /** * @brief Prints entered keys to the console. * * @param keys currently typed keys. */ void writeInput(terminal::state keys) { // FIXME: Do not duplicate lines when line overflows // possible mitigation: only write one line // FIXME: flickering cursor::setX(1); std::cout << "\033[0K" << "> "; for(auto it = keys.keys.begin(); it != keys.keys.end(); it++) { std::cout << *it; } cursor::setX(3+keys.cursorPos); } /** * @brief Writes result line with the result while in typing mode * * @param string the result * @param paranthesis missing paranthesis count, negative if misses left paranthesis * @param calcuationValid is calculation valid * @param inputSize the current input size (used to where display missing paranthesis) */ void writeResultLine( const std::string string, const int paranthesis = 0, const bool calcuationValid = true, const unsigned int inputSize = 20 ) { auto savedCursorPosition = cursor::getPosition().x; if (paranthesis != 0) { cursor::setX(inputSize+5); std::cout << "\033[31m"; if (paranthesis > 4) { std::cout << ") * " << paranthesis; } else if (paranthesis > 0) { for(unsigned short i = 0; i < paranthesis; i++) std::cout << ")"; } else if (paranthesis < 4) { std::cout << "( * " << -paranthesis; } else { //paranthesis is one of -1,-2,-3,-4 for(unsigned short i = 0; i < -paranthesis; i++) std::cout << ")"; } std::cout << "\033[0m"; } std::cout << "\n\033[0K\033[90m"; // FIXME: line overflow handling if (calcuationValid) std::cout << string; else std::cout << "-"; cursor::up(); cursor::setX(savedCursorPosition); std::cout << "\033[0m"; } /** * @brief Writes result line with the result while in typing mode * * @param result the calculation result * @param inputSize the current input size (used to where display missing paranthesis) */ void writeResultLine(Calculator::parseAndCalculateResult result, const unsigned int inputSize) { std::stringstream result_string; result_string << result.value; writeResultLine(result_string.str(), result.unmatchedParanthesis, result.valid, inputSize); } int main() { #ifdef _WIN32 // https://stackoverflow.com/a/47158348 { // enable virtual terminal for legacy Windows terminals HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE); DWORD consoleMode; GetConsoleMode(console, &consoleMode); consoleMode |= 0x0004; SetConsoleMode(console, consoleMode); } #endif std::setlocale(LC_ALL, ""); std::cout << "type :q to exit, type :h for help\n"; bool exit = false; //should we exit? terminal::state keys; while (!exit) { writeInput(keys); // writeResultLine(""); // background calculation // new std::thread([keys]{ writeResultLine(Calculator::parseAndCaluclate(keys.keys), keys.keys.size()); // }); auto input = cursor::getchar(); // if speciality char if (input.special != 0) { switch (input.code) { case 75: // ARROW_LEFT terminal::key_left(keys); break; case 77: // ARROW_RIGHT terminal::key_right(keys); break; default: #ifdef DEBUG debugKey(input); #endif break; } continue; } else switch (input.code) { case 8: // BACKSPACE terminal::key_backspace(keys); break; case 13: // ENTER std::cout << "\n\033[2K" << Calculator::parseAndCaluclate(keys.keys, true).value << "\n"; keys.cursorPos = 0; keys.keys.clear(); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': case '+': case '-': case '*': case '/': case '(': case ')': terminal::key_insert(keys, input.code); break; case ':': exit |= commands::loop(); break; default: #ifdef DEBUG debugKey(input); #endif break; }; } std::cout << "\033[0m"; return 0; }