From aa065cd89f20ebc45cd49371c1110f962a463a67 Mon Sep 17 00:00:00 2001 From: Matuush Date: Thu, 22 May 2025 22:20:29 +0200 Subject: [PATCH] Encapsulate selection and fragment code better --- editor.hpp | 94 +++++++++++++++++++++++++++++++++++ main.cpp | 97 ++++-------------------------------- selection.cpp | 57 +++++++++++++++++++++ treap.cpp | 96 ++++++++++++++++++++++++++++++++++++ treap.hpp | 134 -------------------------------------------------- 5 files changed, 257 insertions(+), 221 deletions(-) create mode 100644 editor.hpp create mode 100644 selection.cpp create mode 100644 treap.cpp delete mode 100644 treap.hpp diff --git a/editor.hpp b/editor.hpp new file mode 100644 index 0000000..222b0b3 --- /dev/null +++ b/editor.hpp @@ -0,0 +1,94 @@ +#include +#include +#include +#include + +using std::string; + +typedef unsigned long long count_type; + +//// Treap +// Treap node representation of a line +struct line { + count_type priority, size; + string text; + line *left, *right; + + line(count_type _p, string _t) : priority(_p), text(_t), size(1), left(nullptr), right(nullptr) {} +}; +typedef std::pair two_lines; + +// Treap data structure +class treap { + line* root; + + count_type get_size(line* l); + two_lines split(line *l, count_type k); + + line* join(line *a, line *b); + line* join(two_lines two) { return join(two.first, two.second); } + line* find(line* l, count_type k); + +public: + treap() { srand(120); root = nullptr; } + + line* find(count_type k); + string get(count_type k) { return find(k)->text; } + void clear(); + void insert(count_type k, string s); + void append(string s) { insert(size(), s); } + void remove(count_type k); + void pop() { remove(size()); } + count_type size() { return get_size(root); } +}; + +// Position +struct position { + count_type r, c; + position operator+(count_type offset) { return {r + offset, c}; } +}; + + +//// Editor +// Editor macros +#define ESC 27 +#define ENTER 10 +#define BS 127 +#define adds(s) addstr(s.c_str()) + +// Treap access functions +string get_line(count_type r, bool substitute_tab = 1); +count_type get_tab_offset(position p); +void set(position p, char ch); +void new_line(count_type r, string text); +void insert(position p, string t); +void insert(position p, char ch); +void remove(position p, count_type len); +void remove(count_type r); +void append(string t); +count_type get_size(); + +// File operations +bool load(string filename); +bool save(string filename); + +// Edit operations +void clear_line(count_type r); +void print_line(count_type r); +void print_file(count_type start); +void split_line(position p); +void print_input(string text); +count_type get_number(string prompt); +string get_string(string prompt); + +// Selection +class Selection { + treap content; // selection + template + void apply_on_selection(position p, F func, G func2); +public: + position pos; // selection initial position + void remove_selection(position p); + void copy_selection(position p); + void paste_selection(position p); +}; diff --git a/main.cpp b/main.cpp index 582fa67..f1ed4cb 100644 --- a/main.cpp +++ b/main.cpp @@ -1,39 +1,16 @@ -#include -#include -#include -#include - -#include "treap.hpp" - -using std::string; +#include "editor.hpp" #define TAB_SIZE 2 -#define ESC 27 -#define ENTER 10 -#define BS 127 -#define adds(s) addstr(s.c_str()) enum mode_type { INSERT, NORMAL, SELECT }; -struct position { - count_type r, c; - position operator+(count_type offset) { return {r + offset, c}; } -}; - -// Utilities -count_type min(count_type a, count_type b) { return (a <= b) ? a : b; } -count_type max(count_type a, count_type b) { return (a >= b) ? a : b; } - // Global variables treap file; // file representation position cur = {0, 0}; // cursor position count_type file_offset = 0; // terminal file offset -position clp; // selection initial position -treap selection; // selection -string last_find, last_replace; // last find/replace inputs // Accessing the file -string get_line(count_type r, bool substitute_tab = true) { +string get_line(count_type r, bool substitute_tab) { string line = file.get(r); if(!substitute_tab) return line; @@ -157,64 +134,6 @@ string get_string(string prompt) { return s; } -// Selection manipulation -template -void apply_on_selection(position p, F func, G func2) { - // Determine first and last selected position - position start = p, end = clp; - if(clp.r < cur.r || (clp.r == cur.r && clp.c < cur.c)) - start = clp, end = p; - - // Clear previous selection - selection.clear(); - - // Last line start - if(start.r < end.r) - func2(end.r, 0, end.c+1); - // selection.append(get_line(end.r).substr(0, end.c+1)); - - // All complete lines in between - for(count_type r = end.r-1; r > start.r; --r) - func(r); - //selection.append(get_line(r)); - - // First line end - string start_line = get_line(start.r); - count_type size = ((start.r == end.r) ? end.c+1 : start_line.size()) - start.c; - func2(start.r, start.c, size); // append - //selection.insert(0, start_line.substr(start.c, size)); -} -// Removing selection -void remove_selection(position p = cur + file_offset) { - apply_on_selection(p, - [](count_type r){ remove(r); }, - [](count_type r, count_type start_c, count_type size) { remove({r, start_c}, size); } - ); -} -// Copying selection -void copy_selection(position p = cur + file_offset) { - apply_on_selection(p, - [](count_type r){ selection.insert(0, get_line(r)); }, - [](count_type r, count_type start_c, count_type size) { selection.insert(0, get_line(r).substr(start_c, size)); } - ); -} -// Pasting selection -void paste_selection(position p = cur + file_offset) { - if(selection.size() == 0) return; - - // Insert last line inside of this - insert(p, selection.get(selection.size()-1)); - if(selection.size() == 1) return; - - // Insert first line in front and split - split_line(p); - insert(p, selection.get(0)); - if(selection.size() == 2) return; - - // Insert lines - for(count_type i = selection.size()-2; i > 0; --i) - new_line(p.r, selection.get(i)); -} // TODO undo @@ -330,6 +249,10 @@ int main(int argc, char* argv[]) { refresh(); print_file(); + // Variables + string last_find, last_replace; // last find/replace inputs + Selection selection; + mode_type mode = NORMAL; // Main loop @@ -378,7 +301,7 @@ int main(int argc, char* argv[]) { break; case 'v': mode = SELECT; - clp = cur + file_offset; + selection.pos = cur + file_offset; break; case 'f': last_find = get_string("to find"); @@ -411,7 +334,7 @@ int main(int argc, char* argv[]) { print_file(file_offset + cur.r); break; case 'p': - paste_selection(cur + file_offset); + selection.paste_selection(cur + file_offset); print_file(file_offset + cur.r); break; default: @@ -459,11 +382,11 @@ int main(int argc, char* argv[]) { print_file(file_offset); break; case 'v': - copy_selection(cur + file_offset); + selection.copy_selection(cur + file_offset); mode = NORMAL; break; case 'x': - remove_selection(cur + file_offset); + selection.remove_selection(cur + file_offset); if(file_offset + cur.r >= get_size()) jump(cur + file_offset); print_file(); diff --git a/selection.cpp b/selection.cpp new file mode 100644 index 0000000..c689f42 --- /dev/null +++ b/selection.cpp @@ -0,0 +1,57 @@ +#include "editor.hpp" + +// Selection manipulation +template +void Selection::apply_on_selection(position p, F func, G func2) { + // Determine first and last selected position + position start = p, end = pos; + if(pos.r < p.r || (pos.r == p.r && pos.c < p.c)) + start = pos, end = p; + + // Clear previous selection + content.clear(); + + // Last line start + if(start.r < end.r) + func2(end.r, 0, end.c+1, &content); + + // All complete lines in between + for(count_type r = end.r-1; r > start.r; --r) + func(r, &content); + + // First line end + string start_line = get_line(start.r); + count_type size = ((start.r == end.r) ? end.c+1 : start_line.size()) - start.c; + func2(start.r, start.c, size, &content); +} +// Removing selection +void Selection::remove_selection(position p) { + apply_on_selection(p, + [](count_type r, treap* sel){ remove(r); }, + [](count_type r, count_type start_c, count_type size, treap* sel) { remove({r, start_c}, size); } + ); +} +// Copying selection +void Selection::copy_selection(position p) { + apply_on_selection(p, + [](count_type r, treap* sel){ sel->insert(0, get_line(r)); }, + [](count_type r, count_type start_c, count_type size, treap* sel) { sel->insert(0, get_line(r).substr(start_c, size)); } + ); +} +// Pasting selection +void Selection::paste_selection(position p) { + if(content.size() == 0) return; + + // Insert last line inside of this + insert(p, content.get(content.size()-1)); + if(content.size() == 1) return; + + // Insert first line in front and split + split_line(p); + insert(p, content.get(0)); + if(content.size() == 2) return; + + // Insert lines + for(count_type i = content.size()-2; i > 0; --i) + new_line(p.r, content.get(i)); +} diff --git a/treap.cpp b/treap.cpp new file mode 100644 index 0000000..b549282 --- /dev/null +++ b/treap.cpp @@ -0,0 +1,96 @@ +#include "editor.hpp" + +// Treap representation of a file +line* root; + +// Get size uf a subtreap +count_type treap::get_size(line* l) { + if(l == nullptr) return 0; + return l->size; +} + +// Split treap by k-th element +two_lines treap::split(line *l, count_type k) { + if(l == nullptr) return {nullptr, nullptr}; + + if(get_size(l->left) >= k) { + // In the left subtree + auto two = split(l->left, k); + l->left = two.second; + l->size -= get_size(two.first); + return {two.first, l}; + } + else { + // In the right subtree + auto two = split(l->right, k - (1+get_size(l->left))); + l->right = two.first; + l->size -= get_size(two.second); + return {l, two.second}; + } +} + +// Join two treaps +line* treap::join(line *a, line *b) { + if(a == nullptr) return b; + if(b == nullptr) return a; + + if(a->priority < b->priority) { + a->size += get_size(b); + a->right = join(a->right, b); + return a; + } + else { + b->size += get_size(a); + b->left = join(a, b->left); + return b; + } +} + +// Find k-th line of file +line* treap::find(line* l, count_type k) { + if(l == nullptr) return nullptr; + + if(k <= get_size(l->left)) + return find(l->left, k); + else if(k == get_size(l->left)+1) + return l; + else + return find(l->right, k - (1+get_size(l->left)) ); +} + +// File access +line* treap::find(count_type k) { + if(k >= root->size) + return nullptr; + // Don't find index k, but k-th line -> +1 + return find(root, k+1); +} +void treap::clear() { + while(size() > 0) { + auto two = split(root, 1); + root = two.second; + delete two.first; + } +} + +// Line insert +void treap::insert(count_type k, string s) { + line *l = new line(rand(), s); + + if(root == nullptr) { + root = l; + return; + } + + auto two = split(root, k); + two.first = join(two.first, l); + root = join(two); +} +// Line removal +void treap::remove(count_type k) { + auto two = split(root, k+1); + auto first_split = split(two.first, k); + delete first_split.second; + two.first = first_split.first; + root = join(two); +} diff --git a/treap.hpp b/treap.hpp deleted file mode 100644 index b12bf66..0000000 --- a/treap.hpp +++ /dev/null @@ -1,134 +0,0 @@ -#include -#include -#include -#include - -using std::string; -typedef unsigned long long count_type; - -// Treap node representation of a line -struct line { - count_type priority, size; - string text; - line *left, *right; - - line(count_type _p, string _t) : priority(_p), text(_t), size(1), left(nullptr), right(nullptr) {} -}; -typedef std::pair two_lines; - -// Treap representation of a file -class treap { - line* root; - - // Get size uf a subtreap - count_type get_size(line* l) { - if(l == nullptr) return 0; - return l->size; - } - - // Split treap by k-th element - // Hopefully with sizes - two_lines split(line *l, count_type k) { - if(l == nullptr) return {nullptr, nullptr}; - - if(get_size(l->left) >= k) { - // In the left subtree - auto two = split(l->left, k); - l->left = two.second; - l->size -= get_size(two.first); - return {two.first, l}; - } - else { - // In the right subtree - auto two = split(l->right, k - (1+get_size(l->left))); - l->right = two.first; - l->size -= get_size(two.second); - return {l, two.second}; - } - } - - // Join two treaps - // Hopefully with working sizes - line* join(line *a, line *b) { - if(a == nullptr) return b; - if(b == nullptr) return a; - - if(a->priority < b->priority) { - a->size += get_size(b); - a->right = join(a->right, b); - return a; - } - else { - b->size += get_size(a); - b->left = join(a, b->left); - return b; - } - } - line* join(two_lines two) { return join(two.first, two.second); } - - // Find k-th line of file - line* find(line* l, count_type k) { - if(l == nullptr) return nullptr; - - if(k <= get_size(l->left)) - return find(l->left, k); - else if(k == get_size(l->left)+1) - return l; - else - return find(l->right, k - (1+get_size(l->left)) ); - } - -public: - treap() { - srand(120); - root = nullptr; - } - // File access - line* find(count_type k) { - if(k >= root->size) - return nullptr; - // Don't find index k, but k-th line -> +1 - return find(root, k+1); - } - string get(count_type k) { - return find(k)->text; - } - void clear() { - while(size() > 0) { - auto two = split(root, 1); - root = two.second; - delete two.first; - } - } - - // Line insert - void insert(count_type k, string s) { - line *l = new line(rand(), s); - - if(root == nullptr) { - root = l; - return; - } - - auto two = split(root, k); - two.first = join(two.first, l); - root = join(two); - } - void append(string s) { - insert(size(), s); - } - // Line removal - void remove(count_type k) { - auto two = split(root, k+1); - auto first_split = split(two.first, k); - delete first_split.second; - two.first = first_split.first; - root = join(two); - } - void pop() { - remove(size()); - } - count_type size() { - return get_size(root); - } -};