-
Notifications
You must be signed in to change notification settings - Fork 715
History API
This refers to the following issues:
-
Provide all information necessary for a "Persistent Undo" plugin.
-
Provide all information necessary for a tool like parinfer-rust to inspect all the changes to the buffer since it was last seen.
-
Enable for "undojoin"-like functionality: easily amend the current history node.
-
Be easy to parse from POSIX shell.
-
Allow for plugins to implement Vim’s
:earlier
.
Nice to have:
-
Use one variable, allowing history to be replaced with
set-option
. -
Have the format be compact, to avoid environment variable limits.
-
Able to support cursor positions or timestamps for each node in the future.
<history_id> <parent0> <timepoint0> <redo_child0> <modification0.0> <modification0.1> <modification0.2>... <parent1> <timepoint1> <redo_child1> <modification1.0> <modification1.1>... ...
- history_id (integer)
-
The index of the active history node. When setting history data, we need to know which node is supposed to refer to the current buffer contents for purpose of validation, so we need it to be part of the data we are setting.
- parent<n> (integer)
-
Index of the parent of node <n>. The parent of node 0 is
-1
. - timepoint<n> (ISO-8601 timestamp)
-
The time the history node was first committed.
- redo_child<n> (integer)
-
Index of the node to which we will move if the user types
U
. Leaf nodes should have-1
. - modification<n>.<m> (modification)
-
The <m>th modification for node <n>.
Modifications are represented as `op|coord|text` strings. `text` is at the end so it can contain arbitrary text, including pipe symbols, and still be easily parsed by shell.
For example:
1 -1 1 2018-12-31T11:15:56Z '+|1.2|hello world' '-|2.7|foo' 0 2 2018-12-31T11:16:12Z '+|2.2|bar' 1 -1 2018-12-31T11:16:46Z '+|7.16|x'
(Quotes are the quotes which might be added by shell expansion, not part of the format itself.)
Since each history node consists of a variable number of items, processors will need to detect the start of the next record by checking if the current item is a well-formed integer. We can parse the data in POSIX sh like so:
eval set -- "$kak_history"
history_id=$1
shift
node=-1
while [ $# -gt 0 ]; do
node=$(( node + 1 ))
parent=$1
shift
timepoint=$1
shift
redo_child=$1
shift
while [ $# -gt 0 ]; do
case "$1" in
[-+]\|*)
op="${1%%|*}"
tmp="${1#*|}"
coord="${tmp%%|*}"
text="${tmp#*|}"
# Process the modification
shift
;;
*[!0-9]*)
shift # Ignore something unknown
;;
*)
break # Start next record
;;
esac
done
done
Since modifications are tagged with +
or -
in their first field, we can
add more tags. In the documentation, we warn existing processors to ignore
unknown tags.
-
The history ID must refer to a valid node.
-
The parent of node 0 must be
-1
. -
Node 0 must not have any modifications.
-
The graph must be acyclic with respect to parent pointers.
-
The graph must be fully connected; every node must be reachable from the root.
-
Every
redo_child
of an internal node must point to an immediate child node. -
Every
redo_child
of a leaf node must be-1
. -
Working backward from the supplied history ID and the current buffer contents to the root, all modifications which are insertions should be deletable and all deletions should be insertable. This means that the coordinate for each exists and the supplied text for insertions is present at that coordinate.
-
Given the constructed buffer contents for node 0 created in the previous step, it should be possible to reach all leaves by applying the insertions or deletions in every node.
- Normal mode commands
- Avoid the escape key
- Implementing user mode (Leader key)
- Kakoune explain
- Kakoune TV