a simple ncurses-based texteditor for the terminal
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

234 lines
5.5 KiB

#include <Editor.hpp>
#include <fstream>
#include <iostream>
namespace groove {
Editor::Editor(std::string filename) : x(0), y(0), buffer(std::make_unique<Buffer>()),
mode_(Mode::EDIT), filename(filename), offset(0) {
if (!this->load()) {
std::cerr << "Could not open file: '" << this->filename << "', creating it on save.\n";
this->buffer->insert("");
}
}
bool Editor::load() {
std::ifstream file(this->filename.c_str());
if(file.is_open()) {
while(!file.eof()) {
std::string line;
std::getline(file, line);
this->buffer->insert(line);
}
return true;
}
return false;
}
bool Editor::save() {
std::ofstream file(this->filename.c_str());
if(file.is_open()) {
for (auto& line : this->buffer->linebuffer()) {
file << line << std::endl;
}
return true;
}
return false;
}
void groove::Editor::input(int car) {
if (this->mode_ != Mode::SAVE) {
switch (car) {
case KEY_LEFT:
this->left();
return;
case KEY_RIGHT:
this->right();
return;
case KEY_UP:
this->up();
return;
case KEY_DOWN:
this->down();
return;
}
}
switch (this->mode_) {
case Mode::EDIT:
switch (car) {
case 'q':
this->mode_ = Mode::QUIT;
break;
case 'i':
this->mode_ = Mode::INSERT;
break;
case 'a':
this->x = static_cast<int>(this->buffer->at(this->y).length());
this->mode_ = Mode::INSERT;
break;
case 's':
this->mode_ = Mode::SAVE;
break;
case 'c':
this->clipboard = this->buffer->at(this->y);
break;
case 'x':
this->clipboard = this->buffer->at(this->y);
this->buffer->remove(this->y);
break;
case 'p':
this->buffer->insert(this->clipboard, this->y);
this->y++;
this->x = this->buffer->at(this->y).size();
break;
case 'd':
this->buffer->remove(this->y);
break;
}
break;
case Mode::INSERT:
switch (car) {
case 27:
this->mode_ = Mode::EDIT;
break;
case KEY_ENTER:
case 10:
{
std::string appendix;
appendix = "";
if (this->buffer->at(this->y).size() > this->x) {
appendix = this->buffer->at(this->y).substr(this->x, this->buffer->at(this->y).size());
this->buffer->at(this->y) = this->buffer->at(this->y).substr(0, this->x);
}
this->buffer->insert(this->y);
this->y++;
this->buffer->linebuffer().at(this->y) += appendix;
this->x = 0;
}
break;
case KEY_BACKSPACE:
if (this->x - 1 >= 0) {
this->x--;
this->buffer->remove(this->y, this->x);
}
else {
if (this->buffer->at(this->y).size() > 0 && this->y > 0) {
int oldLength = static_cast<int>(this->buffer->at(this->y - 1).size());
this->buffer->at(this->y - 1) += this->buffer->at(this->y);
this->buffer->remove(this->y);
this->y--;
this->x = oldLength;
}
else {
if (this->y - 1 >= 0) {
this->buffer->remove(this->y);
this->y--;
this->x = static_cast<int>(this->buffer->at(this->y).length());
}
}
}
break;
case KEY_DC:
if (this->buffer->at(this->y).length() > this->x)
this->buffer->deleteChar(this->y, this->x);
else {
if (this->buffer->at(this->y).empty() && this->buffer->linebuffer().size() - 1 > this->y)
this->buffer->remove(this->y);
else if (this->buffer->linebuffer().size() - 1 > this->y) {
this->buffer->at(this->y) += this->buffer->at(this->y + 1);
this->buffer->remove(this->y + 1);
}
}
break;
case KEY_BTAB:
case KEY_CTAB:
case KEY_STAB:
case KEY_CATAB:
case 9:
this->buffer->at(this->y).insert(this->x, 4, ' ');
this->x += 4;
break;
default:
{
std::ofstream log("log");
log << car << std::endl;
this->buffer->at(this->y).insert(this->x, 1, char(car));
if (this->lastChar != 195 && this->lastChar != 182)
this->x++;
this->lastChar = char(car);
}
break;
}
break;
case Mode::QUIT:
break;
case Mode::SAVE:
switch (car) {
case 'n':
case 27:
this->mode_ = Mode::EDIT;
break;
case 'y':
if (!this->save())
std::cerr << "Could not write to file: '" << this->filename << "'\n";
this->mode_ = Mode::EDIT;
break;
}
break;
}
}
void Editor::render() {
clear();
for (int i = 0; i < LINES - 1 + this->offset; i++) {
if(i >= this->buffer->linebuffer().size()) {
move(i - this->offset, 0);
clrtoeol();
}
else {
std::string line = /*std::to_string(i) + " | " +*/ this->buffer->at(i);
mvprintw(i - this->offset, 0, line.c_str());
}
clrtoeol();
}
this->status();
move(this->y - this->offset, this->x);
}
void Editor::status() {
std::string status;
switch(this->mode_)
{
case Mode::EDIT:
status = "[E]";
break;
case Mode::INSERT:
status = "[I]";
break;
case Mode::QUIT:
status = "[QUIT]";
break;
}
status += "\t\t" +
std::to_string(this->y) + ", " +
std::to_string(this->x) +
"\t\t\tbuffer: " + std::to_string(this->buffer->linebuffer().size()) +
"\toffset: " + std::to_string(this->offset);
if (this->mode_ == Mode::SAVE)
status = "Save File '" + this->filename + "'? [Y/N]: ";
status += std::string(COLS - status.length(), ' ');
attron(COLOR_PAIR(2));
mvprintw(LINES-1, 0, status.c_str());
//clrtoeol();
attroff(COLOR_PAIR(2));
}
}