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.

154 lines
4.4 KiB

#include <Editor.hpp>
#include <Highlighter.hpp>
#include <fstream>
#include <iostream>
#include <math.h>
namespace groove {
Editor::Editor(std::string filename) : x(0), y(0),
buffer(std::make_unique<Buffer>()), mode_(Mode::EDIT),
filename(filename), offset(0), voffset(0), lineMode(LineMode::RELATIVE),
history(History()), inComment(false) {
this->modes.emplace(Mode::INSERT, std::make_unique<modes::Insert>(*this));
this->modes.emplace(Mode::EDIT, std::make_unique<modes::Edit>(*this));
this->modes.emplace(Mode::QUIT, std::make_unique<modes::Quit>(*this));
this->modes.emplace(Mode::SAVE, std::make_unique<modes::Save>(*this));
this->overlay = newwin(LINES * 0.9, COLS * 0.9, (LINES * 0.1f) / 2.0f, (COLS * 0.1f) / 2.0f);
box(this->overlay, 0, 0);
if (!this->load()) {
std::cerr << "Could not open file: '" << this->filename << "', creating it on save.\n";
this->buffer->insert("");
}
}
bool Editor::load() {
if (this->filename == "") {
this->filename = "unbenannt";
return false;
}
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 c) {
this->modes.at(this->mode_)->input(c);
}
void Editor::render() {
long linenumber = this->offset;
this->vspace = this->lineMode == LineMode::RELATIVE || this->lineMode == LineMode::NUMBERS ?
Editor::Digits(this->buffer->linebuffer().size()) + 2 : 0;
clear();
for (int i = this->offset; i < LINES - 1 + this->offset; i++) {
long ln;
switch (this->lineMode) {
case LineMode::RELATIVE:
ln = static_cast<long>(std::sqrt(std::pow(static_cast<double>(this->y - linenumber), 2)));
ln = ln == 0 ? linenumber : ln;
break;
case LineMode::NUMBERS:
ln = linenumber;
break;
}
if(i >= this->buffer->linebuffer().size()) {
move(i - this->offset, 0);
clrtoeol();
}
else {
std::string line = this->buffer->at(i);
Highlighter highlighter(line);
std::unordered_map<long, std::pair<long, ncurses::Colors>> hilist = highlighter.get();
long x = this->vspace;
long found = -1;
long len = -1;
if (this->lineMode != LineMode::NONE) {
std::string label = std::string(x - Editor::Digits(ln) - 1, ' ');
label += std::to_string(ln) + ' ';
if (linenumber != this->y)
attron(COLOR_PAIR(ncurses::Colors::LINENUMBERS));
mvprintw(i - offset, 0, label.c_str());
if (linenumber != this->y)
attroff(COLOR_PAIR(ncurses::Colors::LINENUMBERS));
}
for (auto& car : line) {
if (car == '*' && this->lastChar == '/')
this->inComment = true;
if (car == '/' && this->lastChar == '*')
this->inComment = false;
if (hilist.find(x - this->vspace) != hilist.end()) {
found = x - this->vspace;
len = hilist.at(x - this->vspace).first;
}
if (found >= 0 && len >= 0) {
if (x - this->vspace >= found && x - this->vspace <= found + len - 1)
attron(COLOR_PAIR(hilist.at(found).second));
else if (x - this->vspace > found && x - this->vspace >= found + len) {
attron(COLOR_PAIR(ncurses::Colors::MAIN));
found = -1;
len = -1;
}
}
if (inComment)
attron(COLOR_PAIR(ncurses::Colors::COMMENTS));
mvaddch(i - this->offset, x , car);
attron(COLOR_PAIR(ncurses::Colors::MAIN));
this->lastChar = car;
x++;
}
//mvprintw(i - this->offset, 0, line.c_str());
}
clrtoeol();
linenumber++;
}
this->status();
move(static_cast<int>(this->y - this->offset), static_cast<int>(this->x + this->vspace));
this->renderOverlay();
}
void Editor::status() {
std::string status;
std::string position = std::to_string(this->y) + ", " + std::to_string(this->x) + " ";
status = this->modes.at(this->mode_)->status();
status += std::string(COLS - status.length() - position.length(), ' ');
status += position;
attron(COLOR_PAIR(ncurses::Colors::STATUSBAR));
mvprintw(LINES-1, 0, status.c_str());
attroff(COLOR_PAIR(ncurses::Colors::STATUSBAR));
}
long Editor::Digits(long number) {
return number > 0 ? static_cast<long>(log10 ((double) number) + 1) : 1;
}
}