zeed/main.cpp

243 lines
4.4 KiB
C++

#include <ncurses.h>
#include <curses.h>
#include <string>
#include <vector>
#include <fstream>
#include "treap.hpp"
using std::string;
using std::vector;
#define ESC 27
#define ENTER 10
#define BS 127
#define adds(s) addstr(s.c_str())
enum mode_type { insert, normal };
// Global variables
treap file;
int row = 0, col = 0;
int file_offset = 0;
// Accessing the file
string get_line(int r) {
string line = (*file.find(file_offset+r)).text;
for(int i = 0; i < line.size(); ++i)
if(line[i] == '\t')
line[i] = ' ';
return line;
}
char get(int r, int s) { return get_line(file_offset+r)[s]; }
void set(int r, int s, char ch) { file.find(file_offset+r)->text[s] = ch; }
void insert_line(int r, string text = "") { file.insert(file_offset+r, text); }
void insert_char(int r, int s, char ch) { file.find(file_offset+r)->text.insert(s, string{ch}); }
void remove_char(int r, int s, int len=1) { file.find(file_offset+r)->text.erase(s,len); }
void remove_line(int r) { file.remove(file_offset+r); }
int get_number() {
char ch = '0';
string s = "";
while(ch >= '0' && ch <= '9') {
s += ch;
ch = getch();
}
return stoi(s);
}
// Load file to buffer
bool load(string filename) {
std::ifstream infile(filename);
if(!infile.good())
return 1;
string line;
while (std::getline(infile, line))
file.insert(file.size(), line);
return 0;
}
// Save file from buffer
bool save(string filename) {
std::ofstream outfile(filename);
if(!outfile.good())
return 1;
for(int i = 0; i < file.size(); ++i)
outfile << get_line(i-file_offset) << std::endl;
return 0;
}
// Clear line
void clear_line(int pos) {
move(pos, 0);
clrtoeol();
}
// Print line
void print_line(int pos) {
clear_line(pos);
move(pos, 0);
adds(get_line(pos));
}
// Print file content
void print_file(int start = 0) {
for(int i = start; i < LINES; i++)
if(file_offset+i < file.size())
print_line(i);
else
clear_line(i);
}
// Splitting lines
string split_line(int r, int s) {
string line = get_line(r);
string ret = line.substr(s, line.size());
remove_char(r, s, line.size()-s);
return ret;
}
// TODO kopirování
// TODO hledání a nahrazování
// TODO undo
// Jump to end of line
void jump_line_end() {
int line_size = get_line(row).size();
if(col > line_size)
col = line_size;
}
// Cursor movement
void move_cursor(char ch) {
switch(ch) {
case 'h':
if(col > 0)
move(row, --col);
break;
case 'j':
if(file_offset + row >= file.size()-1) break;
if(row < LINES-1) {
move(++row, col);
jump_line_end();
}
else if(row == LINES-1) {
file_offset++;
jump_line_end();
print_file();
}
break;
case 'k':
if(row > 0) {
move(--row, col);
jump_line_end();
}
else if(file_offset > 0) {
file_offset--;
jump_line_end();
print_file();
}
break;
case 'l':
if(col < get_line(row).size())
move(row, ++col);
break;
}
}
// Skoky a přesuny
void jump(int r) {
file_offset = std::min(r, std::max((int)(file.size()-LINES), 0));
row = 0;
jump_line_end();
}
int main(int argc, char* argv[]) {
// Check valid filename and load
if(argc <= 1)
return 1;
string filename = argv[1];
if(load(filename))
return 1;
// Init
initscr();
refresh();
print_file();
mode_type mode = normal;
// Main loop
bool run = true;
while(run) {
move(row, col);
char ch = getch();
switch(mode) {
case normal:
print_line(row);
switch(ch) {
case 'h': case 'j': case 'k': case 'l':
move_cursor(ch);
break;
case 'g':
jump(get_number());
print_file();
break;
case 'd':
remove_line(row);
print_file(row);
break;
case 'x':
remove_char(row, col);
print_line(row);
break;
case 'o':
insert_line(row);
print_file(row);
break;
case 'q':
run = false;
break;
case 'w':
save(filename);
break;
case 'i':
mode = insert;
break;
default:
break;
}
break;
case insert:
switch(ch) {
case ESC:
mode = normal;
print_line(row);
break;
case BS:
if(col>0)
remove_char(row, --col);
print_line(row);
break;
case ENTER:
insert_line(row+1, split_line(row, col));
print_file(row++);
jump_line_end();
break;
default:
insert_char(row, col++, ch);
print_line(row);
break;
}
}
refresh();
}
// End
endwin();
return 0;
}