initial commit

development
Michael Ochmann 8 years ago
commit b1db1bcc8a
  1. 2
      .gitignore
  2. 26
      CMakeLists.txt
  3. 25
      main.cpp
  4. 9
      src/Buffer.cpp
  5. 53
      src/Buffer.hpp
  6. 234
      src/Editor.cpp
  7. 82
      src/Editor.hpp
  8. 49
      src/ncurses/ncurses.hpp

2
.gitignore vendored

@ -0,0 +1,2 @@
.idea
build

@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.7)
project(groove C CXX)
set(CMAKE_CXX_STANDARD 14)
include_directories(src)
#set(SOURCE_FILES main.cpp)
file(
GLOB_RECURSE SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp
)
file(
GLOB_RECURSE HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/src/*.h
${CMAKE_CURRENT_SOURCE_DIR}/src/*.hpp
)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/src
)
add_executable(groove main.cpp ${SOURCE_FILES} ${HEADER_FILES})
target_link_libraries(groove ncursesw)

@ -0,0 +1,25 @@
#include <iostream>
#include <ncurses/ncurses.hpp>
#include <Editor.hpp>
int main(int argc, char* argv[]) {
groove::Editor editor;
if (argc > 1)
editor = groove::Editor(argv[1]);
else
editor = groove::Editor();
groove::ncurses::ncurses curses;
curses.init();
curses.flush();
while(editor.mode() != groove::Mode::QUIT)
{
editor.render();
int input = getch(); // Blocking until input
editor.input(input);
}
curses.quit();
return 0;
}

@ -0,0 +1,9 @@
//
// Created by miko on 04.03.17.
//
#include <Buffer.hpp>
namespace groove {
}

@ -0,0 +1,53 @@
#pragma once
#include <vector>
#include <string>
#include <memory>
namespace groove {
class Buffer {
private:
std::vector<std::string> lines;
void removeTabs(std::string& line) {
ulong tab = line.find("\t");
if(tab != line.npos)
this->removeTabs(line.replace(tab, 1, " "));
}
public:
Buffer() : lines(std::vector<std::string>()) {}
std::vector<std::string>& linebuffer() {
return this->lines;
}
void insert(std::string str, int line) {
this->lines.insert(this->lines.begin() + line, str);
this->removeTabs(this->lines.at(line));
}
void insert(std::string line) {
this->removeTabs(line);
this->lines.emplace_back(line);
}
void insert(int after) {
this->lines.insert(this->lines.begin() + after + 1, "");
}
void remove(int line) {
this->lines.erase(this->lines.begin() + line);
}
void remove(int line, int car) {
this->lines.at(line).erase(this->lines.at(line).begin() + car);
}
void deleteChar(int line, int car) {
this->lines.at(line).erase(this->lines.at(line).begin() + car);
}
std::string& at(int line) {
return this->lines.at(line);
}
};
}

@ -0,0 +1,234 @@
#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));
}
}

@ -0,0 +1,82 @@
#pragma once
#include <memory>
#include <Buffer.hpp>
#include <ncurses.h>
namespace groove {
enum class Mode {
INSERT,
EDIT,
SAVE,
QUIT
};
class Editor {
private:
int x, y;
int offset;
char lastChar = 0;
std::unique_ptr<Buffer> buffer;
Mode mode_;
std::string clipboard = "";
std::string filename;
bool load();
bool save();
void status();
void scrollUp() {
if (this->y < this->offset && this->offset > 0)
this->offset--;
}
void scrollDown() {
if (this->y >= LINES - 1)
this->offset++;
}
void left() {
if (this->x - 1 >= 0)
this->x--;
}
void right() {
if (this->x + 1 <= COLS && this->x + 1 <= this->buffer->linebuffer().at(this->y).length())
this->x++;
}
void up() {
if (this->y - 1 >= 0)
this->y--;
else {
return;
}
if (this->x >= this->buffer->linebuffer().at(this->y).length()) {
int length = this->buffer->linebuffer().at(this->y).length();
this->x = length > 0 ? length - 1 : 0;
}
this->scrollUp();
}
void down() {
if (this->y + 1 < this->buffer->linebuffer().size())
this->y++;
else {
return;
}
if (this->x >= this->buffer->linebuffer().at(this->y).length()) {
int length = this->buffer->linebuffer().at(this->y).length();
this->x = length > 0 ? length - 1 : 0;
}
this->scrollDown();
}
public:
Editor() : x(0), y(0), buffer(std::make_unique<Buffer>()), mode_(Mode::EDIT), filename("unbenannt"),
offset(0) {
this->buffer->insert("");
}
Editor(std::string file);
Mode mode() {
return this->mode_;
}
void input(int c);
void render();
};
}

@ -0,0 +1,49 @@
#pragma once
#include <ncurses.h>
namespace groove {
namespace ncurses {
struct Color {
short r, g, b;
Color(short r, short g, short b) :
r(static_cast<short>(r * 0.255)),
g(static_cast<short>(g * 0.255)),
b(static_cast<short>(b * 0.255)) {}
};
class ncurses {
public:
ncurses() {};
void init() {
setlocale(LC_ALL, "");
initscr(); // Start ncurses mode
noecho(); // Don't echo keystrokes
cbreak(); // Disable line buffering
keypad(stdscr, true); // Enable special keys to be recorde
start_color();
init_pair(1, COLOR_WHITE, COLOR_BLACK);
init_pair(2, COLOR_WHITE, COLOR_MAGENTA);
if (can_change_color()) {
Color grey(39, 40, 34);
Color pink(255, 0, 103);
init_color(COLOR_BLACK, grey.r, grey.g, grey.b);
init_color(COLOR_MAGENTA, pink.r, pink.g, pink.b);
}
attron(COLOR_PAIR(1));
}
void flush() {
refresh();
}
void quit() {
endwin();
}
};
}
}
Loading…
Cancel
Save