diff --git a/DOC.md b/DOC.md new file mode 100644 index 0000000..1badc9e --- /dev/null +++ b/DOC.md @@ -0,0 +1,108 @@ +# How Ze works on the inside + +## Terminal viewing + +Viewing is done by remembering a file offset for the window. +For example a window viewing 60 lines on file offset 2 would show lines from 2 to 61. +Then we have a cursor, which just represents a row-position and a column-position. +With those two, we can interact with lines, where we have cursor, jump to certain lines and generally move the cursor. + +## Overview + +Ze represents the file as a *treap*. +A treap is a randomized search tree, which is a binary search tree for its keys and a max-heap for their *priorities*. +Internally, the treap operation do not based on node keys, but the sizes of their subtrees - this applies for the b.s.t. attributes. +Nodes of this treap contain lines from the file. +The treap is *semi-persistent*, which means it remembers all of its versions and can modify the last one. +On a higher level, the editor repeatedly takes user input and does corresponding actions. +Those actions are divided into three modes: *normal*, *insert* and *select*. +It uses `ncurses` c library for handling terminal input/output. + +## Treap Semi-persistence + +Ze uses a semi-persistence technique of remembering paths from root to a leaf. + +The main idea is that whenever an editation step changes the treap, only nodes on such a path are changed. +This means that it is sufficient only to remember those paths. + +With this method, the version of the treap is represented by the latest root node. +The root then remembers its son, which is on the change-path and so on. +Roll-back is done simply by following the latest path and erasing nodes it contains. + +## Treap meta-operations + +The core of all editation steps are three operations: *insert*, *remove* and *update*. +Every other operation can wrap something around these three. + +Sometimes that includes using more of them - for that scenario the treap also remembers how many of these meta-operations were used. +Undo is then just erasing as many versions as the editation step used. +As an added bonus, it also remembers the line changed, which makes it possible to jump on the line, where the change occured. + +### Insert + +For insert, we need two modes - with and without version-change. +That is because of treap build - because of it we can just do as many inserts as there are lines of the loaded file and take it as an initial version. + +The new-version-remembering mode works recursivelly - starting with root, it decides whether the left sons subtree has higher or the same size as is the desired index where a new line should be inserted. +If yes, then it calls itself on the left son, otherwise on the right son but with an index, that has the size of the left subtree + 1 subtracted from it. +When it is called on a non-existent node, it creates a new node and returns it. + +With each return, a new node is created with the appropriate son pointer and it's remembered as the next node on its version path. +But that alone wouldn't suffice, because the treap also acts as a heap. +Here come node rotations in play. +If a returned node has higher priority than the original node, they are rotated to suit the heap rules. + +At last, the treap remembers a new root, representing a new version. + +The version-not-remembering mode works almost the same, but not creating new nodes, but instead modifying the treap. + +### Remove + +Remove doesn't need the option not to remember a new version, but it's a little more complicated. +If we're still chasing the node to remove, we simply follow the path to it, same as with insert. + +But when we find the node, then comes the fun. +If any one of the removed nodes sons are non-existent, the removed node is replaced by one that exists, if there is one. +But if both sons are real, we pick the one with higher priority to replace the removed node. +We do this with a handy rotation, which keeps b.s.t. rules, but gets the higher-priority son higher. +Then, when we have the desired son where we want him, we call the remove recursively on the node, we put lower. +Internally, this is done by making a permanent copy of the son and a temporary copy of the removed node, so we can rotate them and not affect the previous versions. + +Each return then creates a new node, just as with an insert. + +### Update + +With the knowledge of insert and delete, update is pretty simple. + +We find the desired point to update by following sizes of subtrees just as with the previous two operations. +Then, when we find it, we create a new, identical node with the new text and return that. +Then with each return, we create our trail of breadcrumbs. + +## Other editation actions + +Everything else, which changes the treap in any way, can be done by using these three meta-operations. + +### Select mode and selection + +Operations on selected text are generalized by a function called `apply_on_selection()`. +It just takes a function to apply to the lines selected in the file and applies it on them. + +It can remove the selected text from the file - that is done with treap removes and updates on the edges. +It can copy the selected text into the selectoin. + +The selection is just a vector of lines. +We can paste them into the file afterwards. + +### Insert mode + +One write on one line should create only one version. +That is accomplished by buffering changes to one line and applying them afterwards. +Other than that, we are just updating specific lines. + +### Find and replace + +We iterate through the file, finding incremental indexes. +We go through each of these lines and search the desired substring. + +Then a find just moves the cursor there. +A replace does an update on this line, changing the substring to something else.