#include #include #include #include #include #include "stringutils.h" #include "typer.h" #include void Typer::ProcessFile(std::string fname) { m_scrRow = 0; m_scrCol = 0; ReadFile(fname); ComputeDiffs(); OnStart(); for (size_t i = 0; i < m_lines.size(); i++) { Line& line = m_lines[i]; // std::cout << "---------\n"; // std::cout << "++ " << line.prio << " : " << line.index << " : [ "; // for (size_t j = 0; j < SIMILARITY_LINE_COUNT; j++) // std::cout << line.similarity[j] << " "; // std::cout << "] : " << line.text << "\n\n"; std::pair lineOut = std::make_pair(line.index, line.text); // Find insertion position auto insertRowIt = std::lower_bound(m_scrOutput.begin(), m_scrOutput.end(), lineOut); size_t insertRow = static_cast(insertRowIt - m_scrOutput.begin()); // Insert row - there are 5 cases // 1. we are on the previous row: End, Return, type row // 2. we are at (0, 0) and nothing is typed: type row // 3. we are on insertRow, Home + type row + press Return // 4. we must insert below last row, navigate to last row, End, Return, type row // 5. we are anywhere else, navigate to (insertRow, 0), press Return, go up and type row if (insertRow > 0 && m_scrRow == insertRow - 1) { NavigateToCol(COL_END); Newline(); TypeString(line.text); } else if (m_scrOutput.empty()) { TypeString(line.text); } else if (m_scrRow == insertRow && insertRow < m_scrOutput.size() && m_scrOutput[insertRow].second.empty()) { NavigateToCol(COL_HOME); TypeString(line.text); Newline(); } else if (insertRow == m_scrOutput.size()) { NavigateTo(insertRow - 1, COL_END); Newline(); TypeString(line.text); } else { NavigateTo(insertRow, COL_HOME); Newline(); NavigateToRow(insertRow); TypeString(line.text); } // Synchronize screen output m_scrOutput.insert(insertRowIt, lineOut); } } void Typer::TogglePaused() { m_keyHandler->TogglePaused(); } int Typer::GetLinePriority(std::string &line) { int prio = 0; if (line.empty()) { return prio; } if (!std::isdigit(line[0])) { return prio; } std::istringstream stream(line); stream >> prio; line = line.substr(static_cast(stream.tellg()) + 1u); return prio; } void Typer::ReadFile(std::string fname) { std::ifstream in; std::string line; int prio; size_t index = 0; in.open(fname, std::ios::in); if (!in) { std::cerr << "Failed to open file " << fname << "\n"; exit(2); } std::map, std::string> lines; while (std::getline(in, line)) { trim(line); prio = GetLinePriority(line); lines.emplace(std::make_pair(prio, ++index), line); } // Put sorted lines in m_lines vector for (auto line : lines) m_lines.push_back(Line(line.first.first, line.first.second, line.second)); } void Typer::ComputeDiffs() { for (size_t i = 0; i < m_lines.size(); i++) { m_lines[i].similarity.fill(0); for (size_t j = 0; j < SIMILARITY_LINE_COUNT && j < i; j++) { std::string a = m_lines[i].text; std::string b = m_lines[i - j - 1].text; if (a.size() > 0 || b.size() > 10) { dtl::Diff diff(a, b); diff.onOnlyEditDistance(); diff.compose(); long long dist = diff.getEditDistance(); m_lines[i].similarity[j] = 1.0f - static_cast(dist) / static_cast(a.size() + b.size()); } else { m_lines[i].similarity[j] = 1.0f; } } } } void Typer::Newline() { KeyNewline(); m_scrRow++; m_scrCol = 0; } void Typer::TypeString(std::string str) { KeyString(str); m_scrCol = str.size(); } void Typer::NavigateTo(size_t row, size_t col) { NavigateToRow(row); NavigateToCol(col); } void Typer::NavigateToRow(size_t row) { if (m_scrRow < row) { for (; m_scrRow < row && m_scrRow < m_scrOutput.size(); m_scrRow++) { KeyDown(); m_scrCol = std::min(m_scrCol, m_scrOutput[m_scrRow].second.size()); } } else { for (; m_scrRow > row; m_scrRow--) { KeyUp(); m_scrCol = std::min(m_scrCol, m_scrOutput[m_scrRow].second.size()); } } m_scrCol = std::min(m_scrCol, m_scrOutput[m_scrRow].second.size()); } void Typer::NavigateToCol(size_t col) { size_t rowLen = m_scrOutput[m_scrRow].second.size(); if (col == COL_HOME && m_scrCol != 0) { KeyHome(); m_scrCol = 0; } else if (col == COL_END && m_scrCol != rowLen) { KeyEnd(); m_scrCol = rowLen; } else if (m_scrCol < col) { for (; m_scrCol < col && m_scrCol < rowLen; m_scrCol++) { KeyRight(); } } else if (m_scrCol > col) { for (; m_scrCol > col; m_scrCol--) { KeyLeft(); } } } bool Typer::IsKeyShifted(char c) { static const std::string shiftedKeys = "~!@#$%^&*()_+{}:\"|<>?>"; if (isalpha(c)) { return isupper(c); } if (isdigit(c)) { return false; } return (shiftedKeys.find(c) != std::string::npos); } void Typer::KeyUp() { m_keyHandler->Key(SpecialKey::UP); } void Typer::KeyDown() { m_keyHandler->Key(SpecialKey::DOWN); } void Typer::KeyLeft() { m_keyHandler->Key(SpecialKey::LEFT); } void Typer::KeyRight() { m_keyHandler->Key(SpecialKey::RIGHT); } void Typer::KeyHome() { m_keyHandler->Key(SpecialKey::HOME); } void Typer::KeyEnd() { m_keyHandler->Key(SpecialKey::END); } void Typer::KeyNewline() { m_keyHandler->Key(SpecialKey::RETURN); } void Typer::KeyString(std::string str) { for (char c : str) m_keyHandler->Key(c, IsKeyShifted(c) ? KM_SHIFT : KM_NONE); }