280 lines
6.3 KiB
C++
280 lines
6.3 KiB
C++
|
#include <fstream>
|
||
|
#include <iostream>
|
||
|
#include <sstream>
|
||
|
#include <unistd.h>
|
||
|
#include <map>
|
||
|
#include "stringutils.h"
|
||
|
#include "typer.h"
|
||
|
#include <dtl/dtl.hpp>
|
||
|
|
||
|
|
||
|
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<size_t, std::string> 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<size_t>(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<size_t>(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::pair<int, size_t>, 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<char, std::string> diff(a, b);
|
||
|
diff.onOnlyEditDistance();
|
||
|
diff.compose();
|
||
|
long long dist = diff.getEditDistance();
|
||
|
|
||
|
m_lines[i].similarity[j] = 1.0f - static_cast<float>(dist) / static_cast<float>(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);
|
||
|
}
|