192 lines
4.6 KiB
C++
192 lines
4.6 KiB
C++
#pragma once
|
|
#include <ncurses.h>
|
|
#include <vector>
|
|
#include <stack>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
|
|
#define TAB_SIZE 8
|
|
constexpr int RANDOM_SEED = 666;
|
|
|
|
using std::string;
|
|
using std::vector;
|
|
using std::stack;
|
|
typedef unsigned long long count_type;
|
|
|
|
// Position
|
|
struct position {
|
|
count_type r, c;
|
|
position operator+(count_type offset) { return {r + offset, c}; }
|
|
};
|
|
|
|
// String utilities
|
|
count_type get_tab_length(count_type c);
|
|
string substitute_tabs(string s);
|
|
count_type get_tab_offset(count_type c, string text);
|
|
|
|
//// Treap
|
|
|
|
// Treap node representation of a line
|
|
struct line {
|
|
count_type priority, size; // Treap innards
|
|
string text; // Content
|
|
line *left, *right; // Sons
|
|
line *next_in_version;
|
|
|
|
void set_left(line *_left) {
|
|
left = _left;
|
|
update_size();
|
|
}
|
|
void set_right(line *_right) {
|
|
right = _right;
|
|
update_size();
|
|
}
|
|
|
|
void update_size() { size = 1 + (left == nullptr ? 0 : left->size) + (right == nullptr ? 0 : right->size); }
|
|
|
|
line(count_type _p, string _t) :
|
|
priority(_p), text(_t), size(1), left(nullptr), right(nullptr), next_in_version(nullptr) {}
|
|
|
|
line(count_type _p, string _t, line *_left, line *_right, line *_next) :
|
|
priority(_p), text(_t), left(_left), right(_right), next_in_version(_next) {
|
|
update_size();
|
|
}
|
|
|
|
line(line *l) :
|
|
priority(l->priority), text(l->text), left(l->left), right(l->right), next_in_version(nullptr) {
|
|
update_size();
|
|
}
|
|
};
|
|
struct change { count_type row, count; };
|
|
|
|
// Treap data structure
|
|
class Treap {
|
|
stack<change> changes;
|
|
stack<line*> root;
|
|
line* get_root() { return root.top(); };
|
|
|
|
line* insert(line *l, count_type k, string s, bool new_version);
|
|
line* remove(line *l, count_type k);
|
|
line* update(line *l, count_type k, string s);
|
|
|
|
line* pick_higher(line *l);
|
|
void delete_version(line *l);
|
|
count_type get_size(line *l);
|
|
count_type get_priority(line *l);
|
|
line* find(line *l, count_type k);
|
|
count_type bulk_find(vector<string> *vec, line *l, count_type k, count_type count);
|
|
|
|
public:
|
|
// General operations
|
|
Treap() { srand(RANDOM_SEED); root.push(nullptr); }
|
|
count_type size() { return get_size(get_root()); }
|
|
void clear();
|
|
|
|
// Versioning
|
|
count_type undo();
|
|
count_type version() { return root.size()-1; }
|
|
void compress_versions(count_type count);
|
|
|
|
// Line getters
|
|
string get_line(count_type r, bool substitute_tab = true);
|
|
vector<string> bulk_get_line(count_type r, count_type count);
|
|
count_type get_tab_offset(position p) { return ::get_tab_offset(p.c, get_line(p.r, 0)); }
|
|
|
|
// Line meta-operations
|
|
void insert(count_type k, string s, bool new_version = true);
|
|
void remove(count_type k);
|
|
void update(count_type k, string s);
|
|
|
|
// Other line operations
|
|
void split_line(position p, bool should_compress = true);
|
|
void merge_line(count_type k, bool should_compress = true);
|
|
void insert(position p, string t);
|
|
void remove(position p, count_type len = 1);
|
|
};
|
|
|
|
//// Selection
|
|
class Selection {
|
|
Treap *file;
|
|
vector<string> content;
|
|
|
|
template <typename F, typename G>
|
|
void apply_on_selection(position p, F func, G func2);
|
|
public:
|
|
Selection() {}
|
|
Selection(Treap *_file) { file = _file; }
|
|
position pos;
|
|
|
|
count_type size() { return file->size(); }
|
|
|
|
void copy_selection(position p);
|
|
count_type remove_selection(position p);
|
|
count_type paste_selection(position p);
|
|
};
|
|
|
|
|
|
//// Editor
|
|
#define ESC 27
|
|
#define ENTER 10
|
|
#define BS 127
|
|
#define adds(s) addstr(s.c_str())
|
|
enum mode_type { INSERT, NORMAL, SELECT };
|
|
struct find_result { bool found; position pos; };
|
|
|
|
class Editor{
|
|
// Editor state
|
|
mode_type mode;
|
|
position cur;
|
|
count_type file_offset;
|
|
|
|
// File
|
|
string filename;
|
|
Treap file;
|
|
|
|
// Editation steps
|
|
string last_find, last_replace;
|
|
Selection selection;
|
|
string current_insert;
|
|
|
|
// Write to file
|
|
void save();
|
|
|
|
// Printing
|
|
void clear_line(count_type i);
|
|
void print_text(count_type i, string text);
|
|
void print_current_line() { print_text(cur.r, file.get_line(file_offset + cur.r)); }
|
|
void print_file(count_type start);
|
|
|
|
// User input
|
|
template <typename F>
|
|
string get_input(string prompt, F func);
|
|
string get_string(string prompt);
|
|
count_type get_number(string prompt);
|
|
|
|
// Movement
|
|
void jump_line_end();
|
|
void move(position p) { ::move(p.r, p.c); }
|
|
void move_cursor(char ch);
|
|
void jump(count_type r);
|
|
void jump(position p) { jump(p.r); cur.c = p.c; }
|
|
|
|
// Find and replace
|
|
find_result find(string text);
|
|
void replace(position p, count_type length, string text);
|
|
|
|
public:
|
|
Editor(string _filename, Treap &_file) {
|
|
mode = NORMAL;
|
|
cur = {0, 0};
|
|
file_offset = 0;
|
|
|
|
filename = _filename;
|
|
file = _file;
|
|
|
|
selection = Selection(&file);
|
|
current_insert = "";
|
|
print_file(0);
|
|
}
|
|
|
|
// The big function
|
|
bool take_action();
|
|
};
|