#include #include #include #include #include namespace groove { Editor::Editor(std::string filename) : x(0), y(0), buffer(std::make_unique()), mode_(Mode::EDIT), filename(filename), offset(0), voffset(0), lineMode(LineMode::RELATIVE), history(History()), inComment(false) { this->modes.emplace(Mode::INSERT, std::make_unique(*this)); this->modes.emplace(Mode::EDIT, std::make_unique(*this)); this->modes.emplace(Mode::QUIT, std::make_unique(*this)); this->modes.emplace(Mode::SAVE, std::make_unique(*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(std::sqrt(std::pow(static_cast(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> 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(this->y - this->offset), static_cast(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(log10 ((double) number) + 1) : 1; } }