291 lines
6.1 KiB
C++
291 lines
6.1 KiB
C++
#include "everything.hpp"
|
|
|
|
// Save file from buffer
|
|
void Editor::save() {
|
|
std::ofstream outfile(filename);
|
|
if(!outfile.good()) {
|
|
std::cerr << "Bad filename";
|
|
return;
|
|
}
|
|
|
|
for(count_type i = 0; i < file.size(); ++i)
|
|
outfile << file.get_line(i, 0) << std::endl;
|
|
}
|
|
|
|
// Clear line
|
|
void Editor::clear_line(count_type i) {
|
|
::move(i, 0);
|
|
clrtoeol();
|
|
}
|
|
// Print any text
|
|
void Editor::print_text(count_type i, string text) {
|
|
clear_line(i);
|
|
::move(i, 0);
|
|
adds(text);
|
|
}
|
|
// Print file content
|
|
void Editor::print_file(count_type start) {
|
|
auto lines = file.bulk_get_line(start, LINES);
|
|
for(count_type i = 0; i < LINES; i++)
|
|
if(i < lines.size())
|
|
print_text(i, lines[i]);
|
|
else
|
|
clear_line(i);
|
|
}
|
|
// Generic input taking
|
|
template <typename F>
|
|
string Editor::get_input(string prompt, F func) {
|
|
print_text(cur.r, prompt+": ");
|
|
string s = "";
|
|
char ch = getch();
|
|
while((ch != ENTER && func(ch)) || ch == BS) {
|
|
if(ch == BS)
|
|
s.pop_back();
|
|
else
|
|
s += ch;
|
|
print_text(cur.r, prompt+": " + s);
|
|
ch = getch();
|
|
}
|
|
print_current_line();
|
|
return s;
|
|
}
|
|
// Taking user input - string
|
|
string Editor::get_string(string prompt) {
|
|
return get_input(prompt, [](char ch) { return true; });
|
|
}
|
|
// Taking user input - number
|
|
count_type Editor::get_number(string prompt) {
|
|
return stoi(get_input(prompt, [](char ch) { return ch >= '0' && ch <= '9'; }));
|
|
}
|
|
|
|
|
|
// TODO undo
|
|
|
|
|
|
// Jump to end of line
|
|
void Editor::jump_line_end() {
|
|
count_type line_size = file.get_line(file_offset+cur.r).size();
|
|
if(cur.c > line_size)
|
|
cur.c = line_size;
|
|
}
|
|
// Cursor movement
|
|
void Editor::move_cursor(char ch) {
|
|
switch(ch) {
|
|
case 'h':
|
|
if(cur.c > 0) {
|
|
cur.c -= 1;
|
|
move(cur);
|
|
}
|
|
break;
|
|
|
|
case 'j':
|
|
if(file_offset + cur.r >= file.size()-1) break;
|
|
if(cur.r < LINES-1) {
|
|
cur.r += 1;
|
|
move(cur);
|
|
jump_line_end();
|
|
}
|
|
else if(cur.r == LINES-1) {
|
|
file_offset++;
|
|
jump_line_end();
|
|
print_file(file_offset);
|
|
}
|
|
break;
|
|
|
|
case 'k':
|
|
if(cur.r > 0) {
|
|
cur.r -= 1;
|
|
move(cur);
|
|
jump_line_end();
|
|
}
|
|
else if(file_offset > 0) {
|
|
file_offset--;
|
|
jump_line_end();
|
|
print_file(file_offset);
|
|
}
|
|
break;
|
|
|
|
case 'l':
|
|
if(cur.c < file.get_line(file_offset+cur.r).size()) {
|
|
cur.c += 1;
|
|
move(cur);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
// Jump to line
|
|
void Editor::jump(count_type r) {
|
|
if(r >= file.size()) r = file.size()-1;
|
|
else if(r < 0) r = 0;
|
|
|
|
if(r < file_offset)
|
|
file_offset = r;
|
|
else if(r >= file_offset + LINES)
|
|
file_offset = r - LINES+1;
|
|
|
|
cur.r = r - file_offset;
|
|
jump_line_end();
|
|
move(cur);
|
|
}
|
|
|
|
// Find next string appearance
|
|
std::pair<bool, position> Editor::find(string text) {
|
|
count_type len = text.size();
|
|
count_type file_size = file.size();
|
|
|
|
for(count_type _r = 0; _r < file_size; ++_r) {
|
|
count_type r = (file_offset + cur.r + _r) % file_size;
|
|
|
|
count_type start = ((_r == 0) ? (cur.c+1) : 0);
|
|
count_type pos = file.get_line(r, 1).find(text, start);
|
|
if(pos != string::npos)
|
|
return {true,{r, pos}};
|
|
}
|
|
return {false, position()};
|
|
}
|
|
|
|
bool Editor::take_action() {
|
|
move(cur);
|
|
char ch = getch();
|
|
switch(mode) {
|
|
case NORMAL:
|
|
print_current_line();
|
|
switch(ch) {
|
|
case 'h': case 'j': case 'k': case 'l':
|
|
move_cursor(ch);
|
|
break;
|
|
case 'g':
|
|
jump(get_number("line number"));
|
|
print_file(file_offset);
|
|
break;
|
|
case 'G':
|
|
jump(file.size());
|
|
print_file(file_offset);
|
|
break;
|
|
case 'd':
|
|
file.remove(file_offset + cur.r);
|
|
if(file_offset + cur.r >= file.size())
|
|
jump(cur + file_offset);
|
|
print_file(file_offset);
|
|
break;
|
|
case 'x':
|
|
file.remove(cur + file_offset);
|
|
print_current_line();
|
|
break;
|
|
case 'o':
|
|
file.insert(file_offset + cur.r, "");
|
|
jump_line_end();
|
|
print_file(file_offset);
|
|
break;
|
|
case 'q':
|
|
return false;
|
|
break;
|
|
case 'w':
|
|
save();
|
|
break;
|
|
case 'i':
|
|
mode = INSERT;
|
|
break;
|
|
case 'v':
|
|
mode = SELECT;
|
|
selection.pos = cur + file_offset;
|
|
break;
|
|
case 'f':
|
|
last_find = get_string("to find");
|
|
case 'n':
|
|
{
|
|
auto result = find(last_find);
|
|
if(!result.first)
|
|
break;
|
|
jump(result.second);
|
|
}
|
|
print_file(file_offset);
|
|
break;
|
|
case 's':
|
|
last_find = get_string("to find");
|
|
last_replace = get_string("to replace");
|
|
case 'r':
|
|
{
|
|
auto result = find(last_find);
|
|
if(!result.first)
|
|
break;
|
|
jump(result.second);
|
|
replace(cur + file_offset, last_find.size(), last_replace);
|
|
}
|
|
print_file(file_offset);
|
|
break;
|
|
case 'p':
|
|
selection.paste_selection(cur + file_offset);
|
|
print_file(file_offset);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case INSERT:
|
|
// TODO remake insert mode for better undo
|
|
switch(ch) {
|
|
case ESC:
|
|
mode = NORMAL;
|
|
// Change current row into current_insert TODO
|
|
print_current_line();
|
|
break;
|
|
case BS:
|
|
// Modify current_insert TODO
|
|
if(cur.c > 0) {
|
|
cur.c -= 1;
|
|
file.remove(cur + file_offset);
|
|
}
|
|
print_current_line();
|
|
break;
|
|
case ENTER:
|
|
// Modify current_insert and update TODO
|
|
file.split_line(cur + file_offset);
|
|
print_file(file_offset);
|
|
cur.r++;
|
|
cur.c = 0;
|
|
move(cur);
|
|
break;
|
|
case '\t':
|
|
// Modify current_insert TODO
|
|
file.insert(cur + file_offset, "\t");
|
|
cur.c += TAB_SIZE - (cur.c % TAB_SIZE);
|
|
print_current_line();
|
|
break;
|
|
default:
|
|
// Modify current_insert TODO
|
|
file.insert(cur + file_offset, string(1, ch));
|
|
cur.c += 1;
|
|
print_current_line();
|
|
break;
|
|
}
|
|
break;
|
|
case SELECT:
|
|
print_current_line();
|
|
switch(ch) {
|
|
case 'h': case 'j': case 'k': case 'l':
|
|
move_cursor(ch);
|
|
break;
|
|
case 'g':
|
|
jump(get_number("line number"));
|
|
print_file(file_offset);
|
|
break;
|
|
case 'v':
|
|
selection.copy_selection(cur + file_offset);
|
|
mode = NORMAL;
|
|
break;
|
|
case 'x':
|
|
selection.remove_selection(cur + file_offset);
|
|
if(file_offset + cur.r >= file.size())
|
|
jump(cur + file_offset);
|
|
print_file(file_offset);
|
|
mode = NORMAL;
|
|
break;
|
|
default:
|
|
mode = NORMAL;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return true;
|
|
}
|