#pragma once #include #include #include #include #include #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 changes; stack 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, bool new_version); 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 *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 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, bool new_version = true); // 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; Treap content; template 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 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(); };