mirror of
https://github.com/neovim/neovim.git
synced 2025-09-08 12:28:18 +00:00
Extmarks: Save extmark undo information to undofile.
This commit is contained in:
114
src/nvim/undo.c
114
src/nvim/undo.c
@@ -594,13 +594,20 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# define UF_START_MAGIC "Vim\237UnDo\345" /* magic at start of undofile */
|
// magic at start of undofile
|
||||||
|
# define UF_START_MAGIC "Vim\237UnDo\345"
|
||||||
# define UF_START_MAGIC_LEN 9
|
# define UF_START_MAGIC_LEN 9
|
||||||
# define UF_HEADER_MAGIC 0x5fd0 /* magic at start of header */
|
// magic at start of header
|
||||||
# define UF_HEADER_END_MAGIC 0xe7aa /* magic after last header */
|
# define UF_HEADER_MAGIC 0x5fd0
|
||||||
# define UF_ENTRY_MAGIC 0xf518 /* magic at start of entry */
|
// magic after last header
|
||||||
# define UF_ENTRY_END_MAGIC 0x3581 /* magic after last entry */
|
# define UF_HEADER_END_MAGIC 0xe7aa
|
||||||
# define UF_VERSION 2 /* 2-byte undofile version number */
|
// magic at start of entry
|
||||||
|
# define UF_ENTRY_MAGIC 0xf518
|
||||||
|
// magic after last entry
|
||||||
|
# define UF_ENTRY_END_MAGIC 0x3581
|
||||||
|
|
||||||
|
// 2-byte undofile version number
|
||||||
|
# define UF_VERSION 3
|
||||||
|
|
||||||
/* extra fields for header */
|
/* extra fields for header */
|
||||||
# define UF_LAST_SAVE_NR 1
|
# define UF_LAST_SAVE_NR 1
|
||||||
@@ -847,6 +854,15 @@ static bool serialize_uhp(bufinfo_T *bi, u_header_T *uhp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
undo_write_bytes(bi, (uintmax_t)UF_ENTRY_END_MAGIC, 2);
|
undo_write_bytes(bi, (uintmax_t)UF_ENTRY_END_MAGIC, 2);
|
||||||
|
|
||||||
|
// Write all extmark undo objects
|
||||||
|
for (size_t i = 0; i < kv_size(uhp->uh_extmark); i++) {
|
||||||
|
if (!serialize_extmark(bi, kv_A(uhp->uh_extmark, i))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
undo_write_bytes(bi, (uintmax_t)UF_ENTRY_END_MAGIC, 2);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -928,9 +944,95 @@ static u_header_T *unserialize_uhp(bufinfo_T *bi,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unserialize all extmark undo information
|
||||||
|
ExtmarkUndoObject *extup;
|
||||||
|
kv_init(uhp->uh_extmark);
|
||||||
|
|
||||||
|
while ((c = undo_read_2c(bi)) == UF_ENTRY_MAGIC) {
|
||||||
|
bool error = false;
|
||||||
|
extup = unserialize_extmark(bi, &error, file_name);
|
||||||
|
if (error) {
|
||||||
|
kv_destroy(uhp->uh_extmark);
|
||||||
|
xfree(extup);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
kv_push(uhp->uh_extmark, *extup);
|
||||||
|
xfree(extup);
|
||||||
|
}
|
||||||
|
if (c != UF_ENTRY_END_MAGIC) {
|
||||||
|
corruption_error("entry end", file_name);
|
||||||
|
u_free_uhp(uhp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return uhp;
|
return uhp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool serialize_extmark(bufinfo_T *bi, ExtmarkUndoObject extup)
|
||||||
|
{
|
||||||
|
if (extup.type == kExtmarkSplice) {
|
||||||
|
undo_write_bytes(bi, (uintmax_t)UF_ENTRY_MAGIC, 2);
|
||||||
|
undo_write_bytes(bi, (uintmax_t)extup.type, 4);
|
||||||
|
if (!undo_write(bi, (uint8_t *)&(extup.data.splice),
|
||||||
|
sizeof(ExtmarkSplice))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (extup.type == kExtmarkMove) {
|
||||||
|
undo_write_bytes(bi, (uintmax_t)UF_ENTRY_MAGIC, 2);
|
||||||
|
undo_write_bytes(bi, (uintmax_t)extup.type, 4);
|
||||||
|
if (!undo_write(bi, (uint8_t *)&(extup.data.move), sizeof(ExtmarkMove))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Note: We do not serialize ExtmarkSavePos information, since
|
||||||
|
// buffer marktrees are not retained when closing/reopening a file
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ExtmarkUndoObject *unserialize_extmark(bufinfo_T *bi, bool *error,
|
||||||
|
const char *filename)
|
||||||
|
{
|
||||||
|
UndoObjectType type;
|
||||||
|
uint8_t *buf = NULL;
|
||||||
|
size_t n_elems;
|
||||||
|
|
||||||
|
ExtmarkUndoObject *extup = xmalloc(sizeof(ExtmarkUndoObject));
|
||||||
|
|
||||||
|
type = (UndoObjectType)undo_read_4c(bi);
|
||||||
|
extup->type = type;
|
||||||
|
if (type == kExtmarkSplice) {
|
||||||
|
n_elems = (size_t)sizeof(ExtmarkSplice) / sizeof(uint8_t);
|
||||||
|
buf = xcalloc(sizeof(uint8_t), n_elems);
|
||||||
|
if (!undo_read(bi, buf, n_elems)) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
extup->data.splice = *(ExtmarkSplice *)buf;
|
||||||
|
} else if (type == kExtmarkMove) {
|
||||||
|
n_elems = (size_t)sizeof(ExtmarkMove) / sizeof(uint8_t);
|
||||||
|
buf = xcalloc(sizeof(uint8_t), n_elems);
|
||||||
|
if (!undo_read(bi, buf, n_elems)) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
extup->data.move = *(ExtmarkMove *)buf;
|
||||||
|
} else {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf) {
|
||||||
|
xfree(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return extup;
|
||||||
|
|
||||||
|
error:
|
||||||
|
xfree(extup);
|
||||||
|
if (buf) {
|
||||||
|
xfree(buf);
|
||||||
|
}
|
||||||
|
*error = true;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/// Serializes "uep".
|
/// Serializes "uep".
|
||||||
///
|
///
|
||||||
/// @param bi The buffer information
|
/// @param bi The buffer information
|
||||||
|
@@ -658,8 +658,62 @@ describe('lua: nvim_buf_attach on_bytes', function()
|
|||||||
}
|
}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it("sends events when undoing with undofile", function()
|
||||||
|
write_file("Xtest-undofile", dedent([[
|
||||||
|
12345
|
||||||
|
hello world
|
||||||
|
]]))
|
||||||
|
|
||||||
|
command("e! Xtest-undofile")
|
||||||
|
command("set undodir=. | set undofile")
|
||||||
|
|
||||||
|
local ns = helpers.request('nvim_create_namespace', "ns1")
|
||||||
|
meths.buf_set_extmark(0, ns, 0, 0, {})
|
||||||
|
|
||||||
|
eq({"12345", "hello world"}, meths.buf_get_lines(0, 0, -1, true))
|
||||||
|
|
||||||
|
-- splice
|
||||||
|
feed("gg0d2l")
|
||||||
|
|
||||||
|
eq({"345", "hello world"}, meths.buf_get_lines(0, 0, -1, true))
|
||||||
|
|
||||||
|
-- move
|
||||||
|
command(".m+1")
|
||||||
|
|
||||||
|
eq({"hello world", "345"}, meths.buf_get_lines(0, 0, -1, true))
|
||||||
|
|
||||||
|
-- reload undofile and undo changes
|
||||||
|
command("w")
|
||||||
|
command("set noundofile")
|
||||||
|
command("bw!")
|
||||||
|
command("e! Xtest-undofile")
|
||||||
|
|
||||||
|
command("set undofile")
|
||||||
|
|
||||||
|
local check_events = setup_eventcheck(verify, nil)
|
||||||
|
|
||||||
|
feed("u")
|
||||||
|
eq({"345", "hello world"}, meths.buf_get_lines(0, 0, -1, true))
|
||||||
|
|
||||||
|
check_events {
|
||||||
|
{ "test1", "bytes", 2, 6, 1, 0, 12, 1, 0, 4, 0, 0, 0 },
|
||||||
|
{ "test1", "bytes", 2, 6, 0, 0, 0, 0, 0, 0, 1, 0, 4 }
|
||||||
|
}
|
||||||
|
|
||||||
|
feed("u")
|
||||||
|
eq({"12345", "hello world"}, meths.buf_get_lines(0, 0, -1, true))
|
||||||
|
|
||||||
|
check_events {
|
||||||
|
{ "test1", "bytes", 2, 8, 0, 0, 0, 0, 0, 0, 0, 2, 2 }
|
||||||
|
}
|
||||||
|
command("bw!")
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
teardown(function()
|
teardown(function()
|
||||||
os.remove "Xtest-reload"
|
os.remove "Xtest-reload"
|
||||||
|
os.remove "Xtest-undofile"
|
||||||
|
os.remove ".Xtest-undofile.un~"
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user