Skip to content

Instantly share code, notes, and snippets.

@sampletext32
Created June 6, 2020 20:40
Show Gist options
  • Save sampletext32/3575c8d7ea20a3d360a94fba9015051f to your computer and use it in GitHub Desktop.
Save sampletext32/3575c8d7ea20a3d360a94fba9015051f to your computer and use it in GitHub Desktop.
// Example program
#include <iostream>
#include <string>
#include <cmath>
#include <algorithm>
#include <sstream>
using u64 = size_t;
enum direction
{
invalid,
left,
right,
up,
down
};
const std::string text =
"01234\n"
"56789\n"
"ab\n"
"cdefg\n"
"\n"
"h\n"
"\n"
"ijklmnop";
const std::string text_big =
" 0 1 2 3 4 \n"
" 5 6 7 8 9 \n"
" a b \n"
" c d e f g \n"
" \n"
" h \n"
" \n"
" i j k l m n o p ";
void refresh()
{
}
std::stringstream debug;
size_t get_pos(direction dir, size_t caret_position)
{
debug.str("");
switch (dir)
{
case left:
{
if (caret_position)
{
caret_position--;
}
break;
}
case right:
{
if (caret_position < text.length())
{
caret_position++;
}
break;
}
case up:
{
debug << "caret_position is " << caret_position << "\n";
u64 current_line_start = text.rfind("\n", caret_position - 1);
if (current_line_start == std::string::npos)
{
// This is the first line, so caret moves to the very beginning
caret_position = 0;
debug << "current_line_start is 'npos', caret_position set to 0\n";
break;
}
else
{
// current line is not first, caret should ignore found '\n'
current_line_start += 1;
debug << "current_line_start is " << current_line_start << "\n";
}
const u64 caret_pos_in_line = caret_position - current_line_start;
debug << "caret_pos_in_line is " << caret_pos_in_line << "\n";
const u64 prev_line_end = current_line_start - 2; // ignore current char and \n before it
debug << "prev_line_end is " << prev_line_end << "\n";
u64 prev_line_start = text.rfind("\n", prev_line_end);
if (prev_line_start == std::string::npos)
{
// if previous line is the first line, there is no '\n' at the beginning
prev_line_start = 0;
debug << "prev_line_start is 'npos', prev_line_start set to 0\n";
}
else
{
prev_line_start += 1;
debug << "current_line_start is " << current_line_start << "\n";
}
const u64 prev_line_length = prev_line_end - prev_line_start + 1; // delta in indexes requires +1
debug << "prev_line_length is " << prev_line_length << "\n";
// TODO : Save caret position to some kind of buffer, so after switching back and forward, caret would be on initial position
if (prev_line_length < caret_pos_in_line)
{
// Previous line is shorter than current caret position, so caret moves to the very end of the previous line
caret_position = prev_line_end + 1;
debug << "prev_line_length " << prev_line_length << " is less than caret_pos_in_line " <<
caret_pos_in_line << ", so caret_position is " << caret_position << "\n";
}
else
{
// Previous line is longer than current, so caret should offset from prev_line_beginning the exact same distance as in current line
caret_position = prev_line_start + caret_pos_in_line;
debug << "prev_line_length " << prev_line_length << " is greater than caret_pos_in_line " <<
caret_pos_in_line << ", so caret_position is set to " << caret_position << "\n";
}
break;
}
case down:
{
u64 current_line_end = text.find("\n", caret_position);
if (current_line_end == std::string::npos)
{
// This is the last line, so caret moves to the very end
caret_position = text.length();
debug << "current_line_end is 'npos', caret_position set to " << text.length() << "\n";
break;
}
else
{
// move to the last character of the current line
current_line_end -= 1;
debug << "current_line_end is " << current_line_end << "\n";
}
u64 current_line_start = text.rfind("\n", current_line_end);
if (current_line_start == std::string::npos)
{
// if current line is the first one - there is no '\n' before it, so line starts from index 0
current_line_start = 0;
debug << "current_line_start is 'npos', caret_position set to 0\n";
}
else
{
// if line is not first, than '\n' was found and caret should ignore \n
current_line_start += 1;
debug << "current_line_start is " << current_line_start << "\n";
}
const u64 caret_pos_in_line = caret_position - current_line_start;
debug << "caret_pos_in_line is " << caret_pos_in_line << "\n";
const u64 next_line_start = current_line_end + 2; // ignore last char and \n
debug << "next_line_start is " << next_line_start << "\n";
u64 next_line_end = text.find("\n", next_line_start);
if (next_line_end == std::string::npos)
{
// if next line is the last line, there is no '\n' at the end, so we check 'find' result
next_line_end = text.length() - 1;
debug << "next_line_end is 'npos', next_line_end set to " << next_line_end << "\n";
}
else
{
next_line_end -= 1; // move to the last char in the line
debug << "next_line_end is " << next_line_end << "\n";
}
const u64 next_line_length = next_line_end - next_line_start + 1;
debug << "next_line_length is " << next_line_length << "\n";
// TODO : Save caret position to some kind of buffer, so after switching back and forward, caret would be on initial position
if (next_line_length < caret_pos_in_line)
{
// Next line is shorter than current caret position, so caret moves to the very end of the next line
caret_position = next_line_end + 1;
debug << "next_line_length " << next_line_length << " is less than caret_pos_in_line " <<
caret_pos_in_line << ", so caret_position is " << caret_position << "\n";
}
else
{
// Next line is longer than current, so caret should offset from next_line_start the exact same distance as in current line
caret_position = next_line_start + caret_pos_in_line;
debug << "next_line_length " << next_line_length << " is greater than caret_pos_in_line " <<
caret_pos_in_line << ", so caret_position is set to " << caret_position << "\n";
}
break;
}
}
return caret_position;
}
void print_state(size_t pos)
{
static const size_t size = text.size();
const auto cursor = std::min(pos * 2, text_big.size());
auto textboard = text_big;
textboard[cursor] = '|';
system("cls");
std::cout << debug.str() << "\n";
std::cout << "New pos = " << pos << " = ";
if (pos > size) std::cout << "out of bounds";
else if (pos == size) std::cout << "end";
else if (pos < size && text.at(pos) == '\n') std::cout << "newline";
else std::cout << text.at(pos);
std::cout << "\n\n\n";
std::cout << textboard;
std::cout << "\n\n\n";
std::cout << "Enter Direction (wasd): ";
};
direction get_dir(const std::string& key)
{
if (key == "w") return direction::up;
if (key == "a") return direction::left;
if (key == "s") return direction::down;
if (key == "d") return direction::right;
return direction::invalid;
};
int main()
{
size_t pos = 0;
while (true)
{
print_state(pos);
// Get new input from console
std::string cmd;
getline(std::cin, cmd);
// Convert input to direction
const auto dir = get_dir(cmd);
if (dir == direction::invalid)
continue;
// Get new position
pos = get_pos(dir, pos);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment