Add 'history' and 'uncommitted_modifications' expansions
This commit is contained in:
parent
62b4780e07
commit
b03b51d27a
|
@ -258,6 +258,18 @@ The following expansions are supported (with required context _in italics_):
|
||||||
the text of the error that cancelled execution of the <commands> parameter
|
the text of the error that cancelled execution of the <commands> parameter
|
||||||
(or the previous <on_error_commands> parameter)
|
(or the previous <on_error_commands> parameter)
|
||||||
|
|
||||||
|
*%val{history}*::
|
||||||
|
_in buffer, window scope_ +
|
||||||
|
the full change history of the buffer, including undo forks, in terms
|
||||||
|
of `parent committed redo_child modification0 modification1 ...`
|
||||||
|
entries, where _parent_ is the index of the entry's predecessor (entry
|
||||||
|
0, which is the root of the history tree, will always have `-` here),
|
||||||
|
_committed_ is a count in seconds from Kakoune's steady clock's epoch
|
||||||
|
of the creation of the history entry, _redo_child_ is the index of the
|
||||||
|
child which will be visited for `U` (always `-` at the leaves of the
|
||||||
|
history), and each _modification_ is presented as in
|
||||||
|
`%val{uncommited_changes}`.
|
||||||
|
|
||||||
*%val{history_id}*::
|
*%val{history_id}*::
|
||||||
_in buffer, window scope_ +
|
_in buffer, window scope_ +
|
||||||
history id of the current buffer, an integer value which refers to a
|
history id of the current buffer, an integer value which refers to a
|
||||||
|
@ -353,6 +365,15 @@ The following expansions are supported (with required context _in italics_):
|
||||||
buffer is modified, including undoing and redoing previous modifications
|
buffer is modified, including undoing and redoing previous modifications
|
||||||
(see also `%val{history_id}`)
|
(see also `%val{history_id}`)
|
||||||
|
|
||||||
|
*%val{uncommitted_modifications}*::
|
||||||
|
_in buffer, window scope_ +
|
||||||
|
a list of quoted insertions (in the format `+line.column|text`) and
|
||||||
|
deletions (`-line.column|text`) not yet saved to the history (e.g. typing
|
||||||
|
in insert mode before pressing `<esc>`), where _line_ is the 1-based line
|
||||||
|
of the change, _column_ is the 1-based _byte_ of the change start (see
|
||||||
|
`%val{cursor_column}`), and _text_ is the content of the insertion or
|
||||||
|
deletion (see also `%val{history}`)
|
||||||
|
|
||||||
*%val{user_modes}*::
|
*%val{user_modes}*::
|
||||||
unquoted list of user modes.
|
unquoted list of user modes.
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ static void apply_options(OptionManager& options, const ParsedLines& parsed_line
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer::HistoryNode::HistoryNode(HistoryId parent)
|
Buffer::HistoryNode::HistoryNode(HistoryId parent)
|
||||||
: parent{parent}, timepoint{Clock::now()}
|
: parent{parent}, committed{Clock::now()}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Buffer::Buffer(String name, Flags flags, StringView data,
|
Buffer::Buffer(String name, Flags flags, StringView data,
|
||||||
|
@ -231,20 +231,10 @@ String Buffer::string(BufferCoord begin, BufferCoord end) const
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Modification holds a single atomic modification to Buffer
|
Buffer::Modification Buffer::Modification::inverse() const
|
||||||
struct Buffer::Modification
|
|
||||||
{
|
|
||||||
enum Type { Insert, Erase };
|
|
||||||
|
|
||||||
Type type;
|
|
||||||
BufferCoord coord;
|
|
||||||
StringDataPtr content;
|
|
||||||
|
|
||||||
Modification inverse() const
|
|
||||||
{
|
{
|
||||||
return {type == Insert ? Erase : Insert, coord, content};
|
return {type == Insert ? Erase : Insert, coord, content};
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
void Buffer::reload(StringView data, timespec fs_timestamp)
|
void Buffer::reload(StringView data, timespec fs_timestamp)
|
||||||
{
|
{
|
||||||
|
|
|
@ -230,14 +230,40 @@ public:
|
||||||
void on_unregistered();
|
void on_unregistered();
|
||||||
|
|
||||||
void throw_if_read_only() const;
|
void throw_if_read_only() const;
|
||||||
|
|
||||||
|
// A Modification holds a single atomic modification to Buffer
|
||||||
|
struct Modification
|
||||||
|
{
|
||||||
|
enum Type { Insert, Erase };
|
||||||
|
|
||||||
|
Type type;
|
||||||
|
BufferCoord coord;
|
||||||
|
StringDataPtr content;
|
||||||
|
|
||||||
|
Modification inverse() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
using UndoGroup = Vector<Modification, MemoryDomain::BufferMeta>;
|
||||||
|
|
||||||
|
struct HistoryNode : UseMemoryDomain<MemoryDomain::BufferMeta>
|
||||||
|
{
|
||||||
|
HistoryNode(HistoryId parent);
|
||||||
|
|
||||||
|
HistoryId parent;
|
||||||
|
HistoryId redo_child = HistoryId::Invalid;
|
||||||
|
TimePoint committed;
|
||||||
|
UndoGroup undo_group;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Vector<HistoryNode>& history() const { return m_history; }
|
||||||
|
const UndoGroup& current_undo_group() const { return m_current_undo_group; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void on_option_changed(const Option& option) override;
|
void on_option_changed(const Option& option) override;
|
||||||
|
|
||||||
BufferRange do_insert(BufferCoord pos, StringView content);
|
BufferRange do_insert(BufferCoord pos, StringView content);
|
||||||
BufferCoord do_erase(BufferCoord begin, BufferCoord end);
|
BufferCoord do_erase(BufferCoord begin, BufferCoord end);
|
||||||
|
|
||||||
struct Modification;
|
|
||||||
|
|
||||||
void apply_modification(const Modification& modification);
|
void apply_modification(const Modification& modification);
|
||||||
void revert_modification(const Modification& modification);
|
void revert_modification(const Modification& modification);
|
||||||
|
|
||||||
|
@ -264,18 +290,6 @@ private:
|
||||||
String m_display_name;
|
String m_display_name;
|
||||||
Flags m_flags;
|
Flags m_flags;
|
||||||
|
|
||||||
using UndoGroup = Vector<Modification, MemoryDomain::BufferMeta>;
|
|
||||||
|
|
||||||
struct HistoryNode : UseMemoryDomain<MemoryDomain::BufferMeta>
|
|
||||||
{
|
|
||||||
HistoryNode(HistoryId parent);
|
|
||||||
|
|
||||||
HistoryId parent;
|
|
||||||
HistoryId redo_child = HistoryId::Invalid;
|
|
||||||
TimePoint timepoint;
|
|
||||||
UndoGroup undo_group;
|
|
||||||
};
|
|
||||||
|
|
||||||
Vector<HistoryNode> m_history;
|
Vector<HistoryNode> m_history;
|
||||||
HistoryId m_history_id = HistoryId::Invalid;
|
HistoryId m_history_id = HistoryId::Invalid;
|
||||||
HistoryId m_last_save_history_id = HistoryId::Invalid;
|
HistoryId m_last_save_history_id = HistoryId::Invalid;
|
||||||
|
|
|
@ -213,4 +213,47 @@ void write_to_debug_buffer(StringView str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InplaceString<23> to_string(Buffer::HistoryId id)
|
||||||
|
{
|
||||||
|
if (id == Buffer::HistoryId::Invalid) {
|
||||||
|
InplaceString<23> res;
|
||||||
|
res.m_data[0] = '-';
|
||||||
|
res.m_length = 1;
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
return to_string(static_cast<size_t>(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String format_modification(const Buffer::Modification& modification, Quoting quoting)
|
||||||
|
{
|
||||||
|
auto quote = quoter(quoting);
|
||||||
|
return quote(format("{}{}.{}|{}",
|
||||||
|
modification.type == Buffer::Modification::Type::Insert ? '+' : '-',
|
||||||
|
modification.coord.line, modification.coord.column,
|
||||||
|
modification.content->strview()));
|
||||||
|
}
|
||||||
|
|
||||||
|
String history_as_string(const Vector<Buffer::HistoryNode>& history, Quoting quoting)
|
||||||
|
{
|
||||||
|
auto format_history_node = [&](const Buffer::HistoryNode& node) {
|
||||||
|
auto seconds = std::chrono::duration_cast<std::chrono::seconds>(node.committed.time_since_epoch());
|
||||||
|
return format("{} {} {}{}{}",
|
||||||
|
node.parent,
|
||||||
|
seconds.count(),
|
||||||
|
node.redo_child,
|
||||||
|
node.undo_group.empty() ? "" : " ",
|
||||||
|
undo_group_as_string(node.undo_group, quoting));
|
||||||
|
};
|
||||||
|
return join(history |transform(format_history_node), ' ', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
String undo_group_as_string(const Buffer::UndoGroup& undo_group, Quoting quoting)
|
||||||
|
{
|
||||||
|
auto modification_as_string = [&](const Buffer::Modification& modification) {
|
||||||
|
return format_modification(modification, quoting);
|
||||||
|
};
|
||||||
|
return join(undo_group |transform(modification_as_string), ' ', false);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,11 @@ void reload_file_buffer(Buffer& buffer);
|
||||||
|
|
||||||
void write_to_debug_buffer(StringView str);
|
void write_to_debug_buffer(StringView str);
|
||||||
|
|
||||||
|
InplaceString<23> to_string(Buffer::HistoryId id);
|
||||||
|
String format_modification(const Buffer::Modification& modification, Quoting quoting);
|
||||||
|
String history_as_string(const Vector<Buffer::HistoryNode>& history, Quoting quoting);
|
||||||
|
String undo_group_as_string(const Buffer::UndoGroup& undo_group, Quoting quoting);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // buffer_utils_hh_INCLUDED
|
#endif // buffer_utils_hh_INCLUDED
|
||||||
|
|
|
@ -309,6 +309,14 @@ static const EnvVarDesc builtin_env_vars[] = { {
|
||||||
return format("{} {} {} {}", setup.window_pos.line, setup.window_pos.column,
|
return format("{} {} {} {}", setup.window_pos.line, setup.window_pos.column,
|
||||||
setup.window_range.line, setup.window_range.column);
|
setup.window_range.line, setup.window_range.column);
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
"history", false,
|
||||||
|
[](StringView name, const Context& context, Quoting quoting) -> String
|
||||||
|
{ return history_as_string(context.buffer().history(), quoting); }
|
||||||
|
}, {
|
||||||
|
"uncommitted_modifications", false,
|
||||||
|
[](StringView name, const Context& context, Quoting quoting) -> String
|
||||||
|
{ return undo_group_as_string(context.buffer().current_undo_group(), quoting); }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
1
test/compose/history/cmd
Normal file
1
test/compose/history/cmd
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Amiddle<esc><a-f>dd
|
1
test/compose/history/in
Normal file
1
test/compose/history/in
Normal file
|
@ -0,0 +1 @@
|
||||||
|
start
|
1
test/compose/history/kak_quoted_history
Normal file
1
test/compose/history/kak_quoted_history
Normal file
|
@ -0,0 +1 @@
|
||||||
|
- $timestamp 1 0 $timestamp - '+0.5|m' '+0.6|i' '+0.7|d' '+0.8|d' '+0.9|l' '+0.10|e' '-0.8|dle'
|
7
test/compose/history/rc
Normal file
7
test/compose/history/rc
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# Make our expansion have a predictable timestamp
|
||||||
|
hook global ClientClose .* %{
|
||||||
|
evaluate-commands %sh{
|
||||||
|
kak -f 'ghf<space>ec$timestamp<esc>2f<space>ec$timestamp<esc>' <kak_quoted_history >tmp
|
||||||
|
mv tmp kak_quoted_history
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user