autotyper/typer.cpp

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);
}